Integration • 45:51
Mac OS X Leopard lets iChat users share presentations, movies, and documents over a video chat with friends and colleagues. The iChat Theater API gives you a number of approaches for controlling how your application's documents or live window contents are shared. Learn from the iChat engineering team how to get started with this exciting Leopard feature, as well as best practices and performance tips for a great experience.
Speaker: Eric St. Onge
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
My name is Eric St. Onge, and today I'm going to be guiding you through this session. I'm an engineer on the iChat team. So let's go through the agenda today. First, we're going to start off with a very high-level overview to what iChat Theater is. Then we're going to talk about supporting iChat Theater in your own application. And we'll go through the architecture of iChat Theater, supporting iChat Theater via Quick Look, and then actually using a lower-level iChat Theater API. And at the end, we'll have time for questions and answers.
So let's start off with a simple question of what is iChat Theater? So simply put, iChat Theater is-- say you start off with a video conference with me and my friend Peter here. And let's say you have a second application that's, say, showing a slide show. iChat Theater lets you take the content of that slide show and add it to the video conference. So Peter and I could both be looking at the slide show of a zebra at the same time, just using iChat.
Let's also take a moment to talk about what iChat Theater is not. First, iChat Theater is not screen sharing. Screen sharing is a feature of iChat, and it allows for full VNC or remote desktop access to another iChat user. But iChat Theater is different. It's for broadcast only.
iChat Theater is also not video chat in your own application. So this is not, for instance, you know, just a video chat view that you can instantiate in your calculator application. That's not what iChat Theater is. Again, it's just broadcasting via iChat. So there are many things you can use iChat Theater for, for instance, still images, video, or presentations. But let's take a look at actually some of the clients out there that are actually supporting iChat Theater.
The first of which is iPhoto. And this is actually built directly into iChat. Under the File menu, if you choose Share iPhoto with iChat Theater, you'll get a browser that will show you all the photo albums that you have set up in iPhoto. And from that browser, you can just pick an album and choose Share. And then you can actually just share that album over iChat Theater. And it has a little controller on the bottom for some extra controls for moving through the slideshow.
Keynote also provides full support for iChat Theater. So all the transitions and all the effects that you can do in Keynote, you can actually show those over iChat through iChat Theater. But there are third-party apps as well. For those of you who saw Bertrand's Mac OS X State of the Union, he talked about 64-bit and Osiris, which is a powerful medical imaging application. And Osiris actually also includes support for iChat Theater.
So look how happy they are to use iChat Theater. So your users can be this happy too. Another application is Boinks Photo Magico. This is a photo slideshow application that's a little more powerful than iPhoto that gives you better effects and different things you can do. CEI Insight is an engineering visualization application.
This also supports iChat Theater so that you can show visualizations over iChat Theater. And a company called Equinox creates a product called the Tube, which allows you to place shift TV. So you can watch live TV or recorded TV over iChat Theater with a friend. And hopefully, by the end of this session, your app will support iChat Theater, too.
So let's take a moment to talk about how you start iChat Theater. The key point is to keep in mind that iChat Theater is always user-initiated from iChat. You have to do this through a variety of ways. We'll go through in a second. But the easiest way is to go to the File menu, Share File with iChat Theater. And then you can pick a document or an application that you want to share with iChat Theater. You can also drag and drop directly onto a video chat.
So let me take a moment to show you how that works. As you can see here, I just have iChat running, and I'm going to start a video chat with my friend Peter. Hi, Peter. So let's say that I have some photos from a recent trip I took to Africa. What I can do in iChat is I can go to the File menu, and I can go Share a File with iChat Theater.
And then I have those on my desktop, so I'll just navigate to it. And I'll pick a few of those that I want to share. And as you can see, it shows up just directly in the video chat. It expands, and there's a second video stream with my friend's camera video and the photo that we're looking at.
But I can also, you know, directly drag and drop from the Finder if I want to do that. So I'll just take these and drag and drop that way. And as you can see, it's just continuing to play a slideshow. But there are other kinds of media that are supported as well. So let's say I wanted to share a movie. I can just take this video and just drag and drop. Hello. And you can see it just immediately starts playing in iChat Theater, just seamlessly.
So I also mentioned Keynote earlier. So this machine actually does not support Keynote fully for some reason. But normally what would happen is if we were broadcasting over iChat Theater using Keynote, again, you would see the full builds and transitions that you would expect to see in a Keynote presentation. So we can go back to the slides.
Slides, please. OK, so that's iChat Theater. Now let's talk about supporting iChat Theater. And first, we'll start off talking about the architecture. So we saw this diagram a moment ago where there's just a zebra that's flying through an orange bar in the video conference. Let's just go through and kind of fill in some of the gaps as to what is actually happening technically behind the scenes. So first of all, we're actually talking about frames that are moving from an application to iChat to iChat on the other side.
So the important piece of information that you need to notice from this diagram is that iChat to iChat is going over the network. And iChat is packaging up that frame for you. So all you need to kind of look at is an application that is providing video content to iChat.
The other important piece of information here is that your application only exists on one side of this. So your application only needs to exist on the sending side of the video. The other side just needs to have iChat to show the video. So when we talk about supporting iChat Theater, primarily we're talking about the part in your application that is sending frames to iChat.
And let's look at one way that we can support iChat via Quick Look. So here's the architecture diagram again for reference. But Leopard introduced a new feature called Quick Look, which allows fast previews and thumbnails for documents. And Quick Look is responsible for providing thumbnails and those images for Finder.
So Finder can display these in a Quick Look panel and it will also use it for Icon Thumbnails. And this is a plugin that you can build. That API is currently available. But if you have one of these, this actually already supports iChat Theater. So iChat is able to use Quick Look bundles and Quick Look plugins to actually provide that content directly over iChat Theater.
So as far as the details of it, if you already have a Quick Look plugin, or if you plan to build one, there's no extra work that you need to do to get iChat Theater working with that plugin. It should just work right out of the box. But there are a few limitations that you should keep in mind if you choose to do that.
The first of which is that Quick Look is always document-based. If you build an application that hides documents from the users, maybe something like iPhoto or iTunes, where there's just a source and all the files are hidden behind the scenes, Quick Look might not be for you. It's also worth pointing out that Quick Look limits the interactivity. So it's read-only, and it's really only very simple controls like fast-forward, rewind, play/pause, just very basic controls. So if you need more advanced controls than that, you'll probably want to look elsewhere.
It's also worth pointing out that the fidelity is limited. So what this means is that-- I talked about Keynote a moment ago with all the builds and presentations and effects. Applications that don't have Keynote installed will actually just use a Quick Look plug-in to render that Keynote presentation.
But that presentation isn't going to have those effects. It's just going to be just a flat view of that presentation. So Quick Look is a very powerful tool, and I would encourage you to build it in to your application's documents. You should look at session 513, System-wide Previews with Quick Look, for more information on how to build that. So that's Quick Look. And I talked about the limitations. If you want to move past those limitations for more control, there's an API for you. So let's talk about that.
And we'll go into this in some depth. So first we'll talk about what you need to do before you begin. We'll talk about session state, which is how the system is actually working. Then we'll talk about providing video and audio. And then we'll talk about playback controls. So first, let's go back to the architecture diagram to see how the API actually fits into this. So first, let's take a closer look at the application. So your application actually has a two-way channel of communication with iChat.
And iChat is actually talking to a data source within your application. But that data source is not actually talking directly to iChat. It's talking to iChat via the instant message framework. So if we are actually talking about supporting iChat Theater, to get a little more specific, all you need to do is build a data source in your application and use the instant message framework to provide frames to iChat.
So let's talk about what you need to do before you begin actually supporting iChat Theater in your application. So the first thing you have to do is you have to tell the operating system that your app supports iChat Theater. And the way you do this is by adding a key to your application's Info.plist. If your application doesn't really support the concept of a document, so if your application is just capable of providing video, you'll want to add this key directly to the top level of your info.p list.
And this is ls can provide imvideo data source, and set the value to true. If your application supports previews for certain specific document types, you'll just add that same key to the bundle document type definition. So that's what you need to do before you begin. Next, let's look at session state.
So I talked about how iChat Theater uses the Instant Message Framework a moment ago. The class that it actually uses in the Instant Message Framework is called IMAV Manager. And to get access to that, you'll want to import the Instant Message Framework and the IMAV Manager header. And then to get the IMAV Manager, it's just a shared instance of IMAV Manager.
That AV Manager has a state built in. So to get that state, you would just call AV Manager state on the shared instance. And the state will change as iChat Theater prepares to show your application. This is actually a critical step, because if you don't register for these state change notifications, the state will never change. iChat Theater uses this registration to actually handle the registration for your application in iChat. So you have to do this to actually support iChat Theater.
And the way you register for those state changes is you use the IAM Service Notification Center. If any of you saw the Instant Message Framework presentation, this is actually the same notification center you would use for that. And then you'll just add an observer for the IAM AV Manager State Changed Notification.
But let's talk about those states a little bit. So there are six states that iChat Theater will go through, or the AV Manager will go through, that you might need to know about. The first of which is IMAV inactive. And this is an idle state. This means that iChat Theater is not actually doing anything. It's basically waiting for the user to initiate iChat Theater from iChat.
At some point in the future, when the user actually initiates iChat Theater, the state will move to IMAV requested. So at this point, if your application supports documents, The URL to share accessor on the AV Manager will be able to tell you the document that the user asked to share. And when you've loaded that document, you're done what you need to do to start the iChat Theater session, you just call it AV Manager Start.
When you call start, iChat Theater will move to IM AV starting up, which means that the session is being initialized. This usually happens very quickly, often in less than a few seconds. So after starting up, the state will move to IM AV pending. And pending can mean two things.
It can mean that the iChat Theater session is being negotiated and that a video conference is already running. Or it could mean that there is actually no video chat, or a video chat has yet to connect. So there are a couple states, and depending on the state that you're in, it might take a different amount of time.
But the key point is that at this point, while it's pending, no video frames are yet being requested, but they will be shortly. And at that point, when you need to provide video frames, the state will move to IMAV running. And as it says, iChat Theater is running. At this point, as I said, your app should provide audio and video to iChat.
Finally, at the end, the state will move to I am AV shutting down. This means that the AV chat has ended somehow. If you need to do any cleanup for any of the objects you created when starting iChat Theater, you should clean them up here. And there are multiple paths to get to shutting down.
So it's important that your cleanup happens in shutting down rather than at the end of your session or something like that. And finally, at the end, it'll move back to IMEV inactive, which means that, again, it's the unidle state, and it's waiting for the user to initiate iChat Theater.
So let's actually talk about running a session. So I mentioned the video data source a moment ago. And to set the video data source, all you need to do is call set video data source on the shared AV manager. You can also set a few options on the AV Manager, the first of which is video optimization stills. Now, since we're actually talking about running a video conference here, these optimizations actually provide hints to the video conference engine to kind of hint as to what your application is going to be doing, kind of the intent.
Instills optimization means that your application is willing to sacrifice motion-- or motion at the expense of quality. Sorry, other way around. First way. Sorry. So what this means is that if your application is going to show a lot of stills, like a slide show with not much animation, stills might allow the video conference to provide higher resolution videos over the conference.
Now, the thing is that if you are also moving a lot in the video, the codec is not going to be able to handle that as well, because you told it that you were going to provide stills. So you should just keep in mind-- keep that in mind.
You can also say that you want replacement mode. So typically what we saw was your camera being sent with a secondary video source. So replacement mode effectively removes that second video source and replaces your camera output with the video from your application. And there are a couple of reasons why you might want to do that, the first of which is CPU usage. Since you don't have to do the camera processing, you can focus all processing on your application's video. And that might be important, depending on what you're doing.
The second thing to keep in mind is that bandwidth can actually be focused more on your application's video content rather than on the entire video conference. And that could also be important. It's also good to know that replacement might happen without you actually asking for it. So iChat Theater was introduced with Leopard.
So if you're talking with a Leopard or Snow Leopard user, you'll be able to see that advanced kind of split view. But if you're talking with older video chat software or aim for Windows, you're actually always going to see replacement, since those applications don't know how to handle iChat Theater. So as I said before, when the state moves to I am AV requested, you're just going to want to start the AV Manager. And if your application wants to stop it for some reason, you call AV Manager stop.
So that was the session state. Now let's talk about actually providing video. So as I mentioned, we just set the video data source. And there are two kind of objects that you can set as a video data source. The first is an NSView or some common subclasses, which I'll talk about. Otherwise, if it's not one of those common classes, you just have to implement an object or write an object that implements the IAM video data source protocol. And I'll talk about both of these in depth.
The first is an NSU data source. And as I said, the common cases for NSUs are handled for you. And where possible, iChat has tried to hook into the display mechanism for those common cases. But let's talk about what those cases actually are. The first of which is just a standard NS view.
So this is just a very basic NS view. Probably most of you are using those in your application. And iChat will actually directly support these in iChat Theater. And what is actually happening to draw a frame in iChat Theater is that you're rendering your image on the main thread. In the method, display rect, ignoring opacity in context.
Another thing to keep in mind about this is that it's resolution independent. That means that an affine transform has been applied to your view before you draw into it. You should check resolution independence guidelines online to see what this actually means. But the short story of it is that you might be drawing into more or fewer pixels than you are used to drawing into. So I said we try to hook into the display mechanism when we can, and that's basically through set needs display. So if you ever need to force a new frame, you just call set needs display yes.
So that's NSView. The next class is Qt Movie View. And Qt Movie View is a view that is built into Mac OS X that allows you to play back QuickTime movies. And for iChat Theater, we've actually hooked directly into QuickTime to get frames from QuickTime for iChat Theater. So this is rendering off the main thread in QuickTime. And that means that set needs display yes is ignored. QuickTime is handling the drawing of these frames, so it knows when a new frame is allowed or available.
Since QuickTime handles audio as well as video, audio comes for free with Qt Movie Views. So if you have a Qt Movie View that's playing a movie with audio and video, both of those will get sent through iChat Theater if a Qt Movie View is your data source.
And then NSOpenGLView, this is Mac OS X's view for showing OpenGL content. And NSOpenGLView basically reads back a snapshot of the GL context, which means basically copying the pixels. It's capturing on the main thread. But since OpenGL does not necessarily have a common mechanism for updating the screen, you actually always must call setNeedsDisplayYes to get a new frame to iChat Theater, since we have no way of knowing when you're updating the view.
QC view is the Quartz Composition view, or Quartz Composer view. And basically, it's a subclass of NSOpenGL view, so it works similarly. It reads back a snapshot of a GL context, like the NSOpenGL view. But a snapshot is captured for every frame. So since Quartz Composer is going to render every frame on screen, you basically always have full motion video, which means that SetNeedsDisplayYes is ignored, since it knows when to draw frames. And IAMVideoOptimizationStills is also ignored, since Quartz Composer is always moving. It's always full motion video.
So those are the common classes. Now let's talk about some of the limitations of things that are not supported in iChat Theater, the first of which is, unfortunately, core animation. So if you have a layer-backed views, animation is not supported. You'll get basically an incorrectly drawn version of that view or something unexpected. But what you can do is that you can use an NSAnimation context and say, set wants layer no on that view instead. That's a workaround.
Also, since we're hooking into the view mechanism wherever possible, if you have an NS view with a QCGL or QT subview, the rendering mechanisms are different for all of those. So iChat doesn't actually know how to capture the frame or capture the video of those kind of views. So basically, the rendering is only going to include the top level view. If you want to get these into iChat Theater, you will need to manually composite those views. But let me show you a demo of NSU data sources in iChat Theater.
So if I call my friend Peter again. So I have here an iChat Theater sample application. The source code is available to you if you want to follow along. But first, let's actually see what it's doing. So I'll just start iChat Theater. And as you can see, it's got a dropdown, basically a source list with a few different kinds of views, starting with the OpenGL view, an NS view, which is basically a web view, Qt movie view, and a QC view.
Let's start with the NSOpenGL view. There's also a pixel buffer and OpenGL buffer, but we'll get to those later. So if we go and we take the iChat Theater application and we drag and drop onto iChat, You'll see that this application is actually now just actively providing content to iChat Theater. And if we go in, if we change the source, that kind of changes as it goes along.
In the NS view, you can see like this. So the web view is an NS view, but it's also worth noting that a web view can contain QuickTime plug-ins and things like that. So if you wanted to see an example where different rendering paths are not supported, for instance, try going to view a trailer in Safari or something like that or in this view. But let's take a look at the source to see how that's working.
So again, this is the iChat Theater sample, if you want to follow along. And primarily, you saw the user interface. It's very simple. Basically, there is a tab view with multiple views behind it. And the main class that is in charge is in controller.h. And you can see it has the pop-up button, which is basically the source list, the NS tab view, which basically is all the views that we were looking at. And then it has actually accessors to all of those views. So we'll skip the first two, but we saw the web view, the normal GL view, which is the spinning square. It also had a QT movie view and a QC view.
So the QC view and the movie view are actually very simple classes that just support drag and drop of a movie or a composition onto those views. So let's not look at the code for those since it's very simple. And a web view is actually just a public class. So we'll take a closer look at the normal GL view in a moment.
But let's see how the controller is actually working. So if we go to Awake from Nib, you can see it's basically doing some work to set up the tab list. And then at the end, it's doing an initial state synchronization to say, set enable iChat, set enable Theater, yes. So let's see what that does. So if we are enabling iChat Theater, we're going to register for the state change notifications, and then we're going to perform that initial state change. So let's see what that state change actually does.
So as I said before, when the state moved to requested, we need to start the AV Manager. And when the state moves to running, we're going to activate the currently visible tab view. And what that means is that if the tab view is showing a slide show or a movie, we're just going to start playing.
So the video data source is actually set in a delegate method for the tab view, which is tabViewDidSelect tabview item. So this method will be called after the tab view has been selected, and all it does is it gets the AV manager. It activates the tab view if it's running. It sets some optimization options, which we'll go back to in a second. It sets up the audio.
And then it picks the data source. So it knows which view it needs to use for each of the different views, and then sets that as the data source. If we just briefly look at the set optimization options, you'll see that depending if it's showing the pixel buffer or the NS view, we're basically going to just say we want stills.
There's also a replacement option under one of the menu items if you want to turn that on. And you can also enable that as one of the optimizations. Let's take a look at the normal GL view. This was the spinning square. And as you can see, it's just a direct subclass of NSOpenGL view with a start time and a redraw timer.
And the code is also very straightforward. Basically, when the view is created, a view did move to window, gets called, and that creates a frame timer, which gets fired every 30 frames a second. And FrameTimerFire is just going to say, "Set needs display: yes." Since this is an NSOpenGL view, we need to always say we need a new frame.
Then all that's doing is some very basic OpenGL drawings. This is just in DrawRect, which will get called implicitly after set needs display is called. And you can see it's just doing some basic OpenGL operations. So that's the basics of the code. If we can go back to the slides.
So that was a demo of NSU Data Sources in iChat Theater. So that covers the very simple cases that might work for most of you. But if you have something lower level, you might actually need more control. And for that, you should go to the iM Video Data Source Protocol, which will give you precise control over video content, frame-level control over video content.
If you need to do bandwidth optimization, you can also do that, and it also will allow you to take care of frame scheduling and audio synchronization, if you have an advanced application where you need to do that. since the other views we talked about actually don't handle that.
So let's talk about how you actually implement the IAM Video Data Source Protocol. Basically, you need to implement callbacks, and the callbacks exist for two buffer types. The first of which is a CV pixel buffer, just a pixel buffer, or a CV OpenGL buffer, which we'll just say OpenGL buffer. And there are two callbacks, the first of which specifies buffer options. And this will get called immediately after you set the video data source.
There's also a second callback to provide frames that you need to implement. This will get called off the main thread. So basically, to implement the Video Data Threshold Protocol, you need to implement one pair of those methods, so either the pair for pixel buffers or the pair for OpenGL buffers.
Let's take a closer look at the pixel buffers. So as I said, there are two callbacks. The first one is to specify the pixel format, and that is getPixelBufferPixelFormat. So just a very simple example is setting the pixel format to 32 ARGB. The second callback you need to implement provides frames, and that is render into pixel buffer for time. So as you can see, the return value is a bool. If nothing has changed since the last time you provided a frame, you'll return no, otherwise return yes.
And while you are dealing with the pixel buffer, you need to keep in mind that iChat Theater owns the pixel buffer, and you should not retain it. When drawing into it, make sure you first lock the base address. Then you can either fill the buffer directly or create a graphics context and draw into that buffer. When you're done, unlock the base address, and that's about it. So here's a very simple example. So first, if nothing has changed since the last time we drew a frame, just return no.
Otherwise, lock the base address. Then get the width and height of the buffer. Since this is actually an active video conference, the frame rate and the size of the buffer could actually change as the conference is going. So you have to make sure that every time this callback is called, you check the width and the height to see if you need to do something differently.
Next, you need to get the base address of that buffer before you draw into it. Then you can do your drawing code. Unlock the base address when you're done, and return yes. So OpenGL buffers work very similarly. The callback-- the first callback is to specify the OpenGL context in pixel format, and that is getOpenGLBufferContextPixelFormat. And in that, again, you just set the context and set the pixel buffer format-- or set the pixel format. The second callback provides frames, and that is render into OpenGL buffer on screen for time.
And again, if nothing has changed, return no. Also keep in mind, again, do not retain the buffer. But when you actually need to draw, you need to attach the buffer to the context and to the screen that you're drawing on. call flush at the end to make sure that the buffer actually gets flushed, the context gets flushed. So here's a sample implementation that we can walk through. If nothing has changed, return no. Next, we're going to set the CGL macro context to a shared context. And let's take a moment to see what CGL macro context actually does.
So a recent version of Mac OS X introduced the concept of concurrent OpenGL rendering, which essentially means that OpenGL is multithreaded, and there is not necessarily a current OpenGL context. It might vary depending on the thread you're on. So this macro will actually solve that problem for you. So it will actually direct OpenGL to use a specific context.
So if you want to use this macro, you need to import the OpenGL/CGL macro header and then set CGL macro context to the context that you want to use. And to see what this is actually doing, let's say we have a callback thread and a main thread, each of which has their own context.
So if on the callback thread we set it to the shared context and the main thread we set it to the main context, what happens after that macro is called is that every operation that is sent to OpenGL is now focused to the specific context. So if this were not taken care of, for instance, you might end up with a bizarre situation where you're not entirely sure where your OpenGL commands are being sent.
So just keep in mind that if you have multiple contexts, you need to set the CGL macro context to the context you want to draw into. So to go back to the sample implementation, you set the macro context. You attach the buffer to the context and the screen. You get the rect for the buffer, and then you do your OpenGL operations and your drawing, and when you're done, return yes.
So there's one parameter that we didn't talk about yet, which is the for time argument. And as you can see, this exists on both pixel buffers and OpenGL buffers. So what does this actually mean? And what it actually is is it's the time stamp that the frame is being requested. And we give you this because this will actually allow you to synchronize frames. You should set this to the time that the frame that you are returning first appeared on screen. And let's take a look at why you might want to do that.
So let's say that you have a data source with callbacks being called to provide frames, you know, 20 frames a second. And you're drawing to screen 30 times a second, so 30 frames a second. What this means is that when iChat is calling back into your application, it's basically going to miss every third frame.
So the remote side, when you send this over iChat Theater, is basically going to see frames with a lot of jitter. So a frame that should have been short might be long, and a frame that should have been long might be short. So the motion will not look smooth. Basically, what you want to do is you want to adjust the timestamp to when that frame first appeared on screen to kind of match up to when your application showed these frames on screen.
So what this actually means, or what this effectively does, is it drops the third frame. So again, the third frames will still be dropped. So the same number of frames will be sent. But the effect will be much smoother on the remote side. So let me give you an example of this. I am video data source protocols.
So here we are again. Let's start the iChat Theater sample. And we'll go back to the first two sources that we didn't talk about yet. So the Pixel Buffer, which is actually a slideshow, which also has a cool little laser pointer if you want to add that to your application. And open a jail buffer, which is just a very basic progress indicator. And just we can switch between these two. As you can see, it's just an additional view like any of the others. But let's take a look at how that actually works behind the scenes.
So again, we talked about-- we already went over the QC view, the Qt Movie view, the normal GL view, and the web view. So the first sample, the pixel buffer, was a slideshow view. And this is just a very simple class. It's a subclass of NSView. In terms of instance variables, it has a start time and a timer. So like the OpenGL view we saw in the last one, basically it's going to create a timer that fires 30 times a second. And it also has a start and a stop method so that it knows when to start and stop the slide show.
So in terms of implementation, In Awake from Nib, it's going to set up the slideshow. And when this is activated, it's going to be set as the video data source. So again, as the tab switches, it's going to set the video data source. And here you see the video data source implements getPixelBufferPixelFormat, which sets the pixel format to 32 ARGB. And it also implements renderIntoPixelBufferForTime.
So the slideshow is interesting in that the way it actually renders is that with a given set of slides, it knows which slide or which dissolve between those slides it should show at any given point in time. So since the time argument is given, this basically means that we can look at the slide show and see what frame we should pull out to provide to iChat Theater. And as you can see, we do that by get current image.
And that's going to give you the image. But then we're going to lock the base address, create the graphics context, or use the graphics context we've already created. Set the context, draw into it, and flush it. And then at the end, since as you saw it was a slide show, some of the images showed for longer periods of time than others. So we're going to adjust the timestamp back to when that slide first appeared. Then we'll release the context and unlock and return yes.
So next, let's talk about the threaded GL view. This was the progress indicator. And again, this is very simple. It just uses a timer like the others. But it creates a context and a pixel format. So if we look at the implementation of that, again, on viewDidMoveToWindow, it sets up the frame timer.
And it also implements the OpenGL buffer callbacks. So getOpenGLBuffer just basically creates the pixel format here that it wants to use, and it creates the context. Then it sets it to the context passed in and the pixel format as well. And render into OpenGL Buffer for Time, again, is using CGL macro context. Since we created a context above, it's basically going to render on a different context than the main UI.
So again, it's going to attach the buffer to the screen in the context, get the rectangle, set up the OpenGL commands, and then render into that context for the specified time. And it'll just return yes. So that drawing takes place here. You can see it's basically just doing some very basic OpenGL operations to draw that progress indicator.
Okay, we can go back to the slides. So that was the iM Video Data Source Protocol, and again, that's part of the iChat Theater sample if you want to see how that's working in depth. Now let's talk about audio. And audio, actually, in terms of iChat Theater, is very straightforward.
The first thing you need to do is on the video data source, you need to tell it the number of audio channels that you are going to provide. This can be zero, one, or two. iChat Theater actually supports one audio channel, and so it's going to mix this down for you.
But for convenience, we'll say we support two, and you can provide two channels. And then when you've said the number of audio channels you support, when the state is IMAV running, you can ask for the device UID and the channels that are set up for that. And this is actually-- you can use NS Sound to actually play into iChat Theater. So on a sound, you can set the audio device by passing in the playback identifier. Then you can set the channel mapping.
And again, this will map back to the number of channels that you said you wanted earlier. And then finally at the end, when you want to play, just say, my sound play. So it's worth noting that this is actually probably more complicated than most of you need to do.
We've actually written this for you, just sample methods that would just play these sounds, just categories on NS Sound. Those are part of the iChat Theater sample, so we just encourage you to take those sound additions and copy them into your own project to use those in iChat Theater.
But if you need to go lower level than NSSound, you can also use Core Audio, and this is by using a Core Audio device. So if NSSound is too easy for you, you can use the Core Audio code. So again, basically, we're talking about converting from an audio device ID-- from the audio device UID we received from iChat Theater to an audio device in Core Audio. And we'll use an audio value translation that's going to pass in the UID that we start with and the device we want to translate to. And then we'll perform that get property operation to do the translation, which ends up back in the device.
And then you can use the Core Audio device as you would any other Core Audio device. So Core Audio is kind of beyond the scope of this presentation, but if you want to find more about Core Audio, you can check out session 704, Understanding the Architecture of Core Audio. Or if you want to go to a lab, it's lab 7017, the Core Audio lab.
So that was audio. Now let's talk about playback controls. So if you're running on Leopard, basically what you see when you're running iChat Theater is not actually just a simple window with content in it. You're also going to see a second window. So in the case of Quick Look, for instance, here, you're going to see the zebra in a second window.
And that second window might be in your way, and might just be occluding your iChat experience. So we kind of want to improve this. So for Snow Leopard, what we've done is we've refined this. So we're getting rid of that Quick Look panel, and we're moving those controls directly into the iChat window.
So this is new for Snow Leopard, and it's embedded in the video chat. And it's actually API that's available for you as well. But it supports only very basic controls. So play/pause, forward, such as next in a slide show, or backward, which is previous in a slide show, a mute, and a time slider, basically a scrubber like you would see in a video.
So this is an opt-in API only. So if you don't want to use these controls, you don't have to. If you've already supported iChat Theater or have some other solution for controls that you want to continue to use, you can do that. So it's opt-in only. There are two classes, the IMAV Control Bar. And the Control Bar is basically the container for the buttons that you want to use.
And then there is the IMAV control, which is the control that you can put into that container. And basically, there are two types right now-- IMAV button and IMAV slider. And those are the controls that you see in that control bar. And these are roughly parallel to their AppKit counterparts-- NSControl, NSButton, and NSSlider. But it's trimmed down to support just the accessors and setters that can be used in iChat Theater.
So that control bar that you see is actually just available from an AV Manager. So if you just say Shared AV Manager and get the control bar, you'll have that control bar. And then to add buttons to that, the API is very straightforward. The buttons exists as shared instances off the class that they are declared as part of. So for the Play/Pause button, you can call imavbutton Play/PauseButton. And then you can set the state to enabled. And you can set a target and action. So that means that when the button is pressed in iChat, that target and action will be called in your application.
And then when you set it up, you add it to the control bar and it'll show up immediately in iChat, assuming that your application is the one that is providing content to iChat Theater. Enter/remove, it's very similar. You just say remove control, specified control. Or you can just fast remove all controls. So let's take a look at that too. Peter again? So OK, so if we start up the iChat Theater application again.
So basically, if we go to the iChat Theater sample under the Video menu, as I said earlier, if you want to turn on Replace Video, you can do it here. But we're going to turn on Controls. I mean, just flip on that menu item, and as you can see, it just immediately shows up in iChat.
And if we push the buttons here, you can see it changes the view in the other application. And if we want, we can go back here and we can, you know, shut those off, and it just immediately shuts back off. Turn them back on if we wanted to. And that's playback controls. So let's see how that's implemented.
So if we go back to the controller, there is an additional accessor for set enable theater controls. And what that does is basically it gets the control bar from the shared AV manager, like we saw. And if we're enabling, we're going to basically set up a backward button and a forward button. And we're going to set up a target in action to select the previous source or select the next source. So it's basically just going to move through the items available in the dropdown or in the pop-up button.
We can see, so select next source. All it does is just basically select a new source. That will kind of trigger the tab view, did select tab view item callback, and it'll behave as we expect it to. So again, that's really all there is to it. As you can see, it's very little code to add those controls and to get them working with your own application. So let's go back to the slides.
So that was playback controls. And that actually almost wraps it up. So today we talked about what iChat Theater is. We talked about supporting iChat Theater, including an overview of the architecture, how to support iChat Theater via Quick Look, and then an introduction to the lower level API for iChat Theater.
So you can use iChat Theater for sharing and collaboration. You can use iChat Theater to basically show anything that you can show in your application without having to need your application on the other side. So your own users can basically sell your application to their friends. And there are a few options if you want to support iChat Theater.
You can use Quick Look. Or for lower level support, you can go to NSU or the basic subclasses. Or for full control, you can use the IAMvideo data source protocol and implement those callbacks. As I said, Snow Leopard introduces playback controls. So we encourage you to use those to make the experience better for iChat users of your application. And we'd love to hear your feedback basically on the entire process, from starting iChat Theater all the way to the playback controls, which is new for Leopard. We're here to support you.
So for more information, you should contact Matt Drance. You can email him at mdrance at apple.com. You can also join the mailing list for questions about iChat Theater, the Instant Message Framework, or any of the scripting mechanisms that you can use for iChat. That is iChat-dev at lists.apple.com. The sample that we went over today is available from the attendees site, developer.apple.com slash www.attendee. And for related sessions, you should check out session 523, Keeping Users Connected with the Instant Message Framework.
We have a lab tomorrow morning at 9 o'clock if you want to drop by and ask us some questions or if you want any help implementing iChat Theater in your application. And we also talked about Quick Look, so if you want to find out how to implement Quick Look with your own application, check out session 525, System-Wide Previews with Quick Look.