Hardware • 55:02
This session discusses audio services available to applications, including the basic Audio I/O model and how audio hardware is presented to an application. Java APIs that provide access to these services will also be discussed.
Speakers: Jeff Moore, Doug Wyatt, Bill Stewart
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon and welcome to the Audio Services in Mac OS X session. I'm Craig Keithley. I'm the USB and FireWire technology manager in Worldwide Developer Relations. A lot of audio devices these days are moving to FireWire and USB, and we have a great fondness of them. We're especially interested in seeing great FireWire audio devices using the MLan standard in the future. We are working very diligently to add that support in an upcoming OS release. I can't tell you when or where.
The thing that I want to stress as I get ready to introduce the engineering team is that Steve said in his keynote that one of the developer feedback items we got was audio support. And I've been working with the audio team and going through their presentations, and I think you'll be very excited by what we've got. So with that, I'd like to bring up Bill Stewart, the manager of Audio Software Engineering. Thanks.
Okay, so I'd like to just give you some overview of the audio and MIDI services that we have shipping in Mac OS X today. It came out with the first version of Mac OS X. And give you some idea of the sessions that we have at the conference. This is the first session and we're going to be mainly focusing on the lowest levels of the audio system, how hardware is presented to applications, how applications can talk to audio hardware. And there's two sessions tomorrow starting at 3:30 on MIDI and MIDI services that are provided in Mac OS X, as well as the latest session at 5:00 is talking about some high level services such as software synthesizers, audio units and audio unit graphs.
And in the MIDI session tomorrow, we'll actually go through some of the services that we have in the software. So, through some detail about some of the performance and latency characteristics of OS X, there's been some good and bad, usually misinformed information about that. And we'd like to sort of present to you some information that we've got based on some of the tests that we've done. And you saw the keynote on Monday, so there's some information we'd like to give to you. And that'll be mainly in tomorrow's session.
Before I bring up Jeff Moore, who will talk about the bottom layers of the system, I thought I should give you some overview of what is on 10, some of the things that we had in mind when we were designing this system, and some of the concerns that we sought to address by re-architecting the system.
So, I think flexible audio format, what does that mean? Well, we've seen audio come a long way since two channels was the king of the day, and we've now got multi-channel fairly commonly placed in a lot of different areas, not just in the pro audio world, but in consumer devices and games and so forth.
We also realize that there's a need to address the PCM format, which is a standard sort of audio format. We've got the raw sample data there, and there's also a lot of devices coming out now that deal with non-PCM formats, like devices that will take encoded format in, say, AC3 as a DVD player or something. So, we needed to take that into consideration. We also wanted to preserve as much of the information as we could if we're going to be doing signal processing.
A lot of the devices are not just 16-bit devices anymore. You'll have resolutions on the devices up to 24 bits, and when we were discussing this, we thought that the best way to do this, not only from a DSP point of view, but also in terms of representing the hardware, is to present that in a format that is capable of preserving the integrity and the resolution that you require. And also, as many of you are aware, sample rates have gone up quite a long way since 44.1K was the standard. And so we needed to address that issue.
Another thing that we wanted to do in the professional world, you typically see a very strong focus of audio being generated and controlled by one application. And in an operating system level, that is not going to fly or it's not going to be particularly useful for applications that may want to generate audio and they may not be the focus application or they want a sys beep and they're in the background or all kinds of things like that.
So if you're going to have multiple applications talking to the audio system, you've then also got to understand, well, what might be an appropriate latency for one application is not an appropriate latency for another application. So we wanted to design a system that took care of those issues and let applications operate at a level of detail that they were comfortable with.
Another weakness that we saw with the existing sound manager stack on Mac OS Classic systems was we sometimes had no idea what time it was. If you look at the samples that are coming in or samples that are going out, you can sort of guess at some of the time information that should be around those samples, but you may not exactly know what time it is and that has a lot of ramifications for how you deal with synchronization with other media, with hardware that may be doing both video and audio.
So we wanted to address that. And if some of you know my history, I have a particular fondness for Java, so I felt we should present these services not just to C programmers, but also present an API for the Java platform that would be comfortable with the sound. for people that are working in that space.
This is a diagram of the architecture that we have. The white line in the diagram is the difference between the kernel space and then above it is the different user spaces. As you all know, Mac OS X is a memory protected system. Each client has -- each user space has its own memory address mapping. So below the white line you've got the kernel and the I/O in Mac OS X is handled by I/O Kit.
I/O Kit is a set of classes that deal with different types of buses and different types of hardware like PCI, et cetera, FireWire, USB. And the -- above the line, the first layer that you see for audio is called the Audio HAL. HAL stands for Hardware Abstraction Layer. And the main services that you would expect at that point is that the Audio HAL is going to cross the boundaries when it needs to in order to talk to hardware.
And each user client of the system is going to see different versions of the HAL but then there must be some global state if you've got two apps talking to the same device for instance. And so we'll be going through in today's talk about some of the stuff that goes on there.
And then on top of that, in the client process, you have services that in the -- on the left hand side or no, your right hand side, you've got classic and classic talks to the Audio HAL in order to talk to hardware in the same way. In the second process, you might have the Carbon Sound Manager and that talks to the HAL to talk to hardware. And then audio units are some processing units. It's part of the audio toolbox stuff that we'll be going into tomorrow's session at 5:00.
So the Core Audio Framework, we have frameworks on 10 and that's how libraries and their header files are presented to users. The Core Audio Framework has the audio hell, that's where you find that. There's an audio hardware.h file in there that is where you find the APIs and type defs and so forth for interfacing to the audio hell. It has basically the audio device is the primary object, we'll be going through this in some detail today.
Audio Toolbox and Audio Unit Frameworks are the high-level frameworks. I'll be covered in detail tomorrow. Audio Toolbox, the aim there is to provide a set of tools that you can use in your application to do audio tasks like sequencing a MIDI file, dealing with different types of events that might translate to some changes in audio behavior, like generating notes on a software synthesizer or panning a sound from one channel to another over time. And if you've got a sequence of events, you need some object to play it. That's what the music player does. Audio units, I suppose the best way to think about this is like a plug-in.
It's a way of taking audio, of making a component that will take audio in, do something to it and spit audio out. But some audio units might just generate audio. They might not have any audio input. A good example of that would be the software synthesizer. And some audio units may just sort of end there.
You don't see anything come out of them, at least from the application point of view. You might get audio into them and see nothing out. And later on in this talk we'll be talking about a unit we call a default output unit. And I'll leave the details of that until later this afternoon.
Just to talk a little bit about Sound Manager. That's in Carbon. Carbon Sound Manager. It's nearly equivalent API between what's on Tenum, what's in the Classic. There's some deprecated APIs that we removed. One that was very unpopular, but we've been telling you for a long time we're going to remove it anyway, so we thought we would, which is SoundPlay Double Buffer. There is some sample code up on the website if you want to see how you can provide that capability yourself.
I think an important thing to understand about the two, the two platforms, is that they're different roles the Sound Manager performs on both of those platforms. On a Classic system, the Sound Manager is a global state. You can really see the whole state of Sound Manager from all the different applications and stuff by looking at the Sound Manager in a nine. It also provides a hardware model.
We have SDEV components, we have input drivers, input components and things like that, that really do interface directly to the hardware and for better or worse this was the way that, if you wanted Sound Manager and clients of Sound Manager like QuickTime to talk to your audio hardware, you had to write components for the Sound Manager. On Mac OS X, the Sound Manager is quite different.
It's a client of the audio system and the audio system we have on X is really called Core Audio, which is what these talks are about. On Mac OS X, the Sound Manager is per process. You don't have any idea what's going on in another process through Sound Manager calls. It's only what's happening in that particular process. It also does not provide the hardware model.
The lower levels of the Sound Manager on X talk to the hell and the hardware model for audio devices are provided by I/O Kit, specifically by the I/O audio family classes and support capabilities. So that's an important distinction to understand. Another important distinction I think is the Sound Manager has a native format of 16 bit integers.
Doesn't deal very well with formats beyond that. Doesn't deal very well with stereo, with anything beyond stereo. These are all limitations that we hope we've completely gone beyond with Core Audio where you can have N channels of data where you can deal with floating point 32 bit as your primary generic format.
[Transcript missing]
Devices. What devices? Well, Apple currently supports the USB audio class driver, or as I was reminded earlier, USB audio and MIDI. I've got two slides for this. We support obviously built-in hardware. Most of Apple's built-in hardware is 16-bit 44K stereo. USB provides a completely different thing and we'll show you some of the extended work that we're doing to make sure we do support USB audio as we should on the platform later in this session.
Firewire Audio, as Craig mentioned earlier, is a very, we consider this at Apple to be a very important technology going forward for audio, particularly for the pro audio space for the high performance and the kind of stringent demands of pro audio wants. Firewire Audio is really comprised of two things, the 61883-6 transport layer, it took me months to remember that number, and I can get it now, and the MLan connection management. The transport layer is just how do you put audio and MIDI data across Firewire bus.
MLan connection manager is intelligent information that the devices can publish about their capabilities to other Firewire devices and allows for configuration of a network of audio or MIDI devices. We are at Apple a signatory of the MLan connection management stuff and we will certainly be doing, I think, some very interesting work in this sphere going forward. And it's a very similar story for MIDI. We actually do provide a USB MIDI class driver.
We also, in our developer example code, provide a sample code for vendor specific USB drivers, so it's very easy if you're publishing a vendor specific USB MIDI device to just sort of take that code as a basis and then provide a driver, which many people in this room will probably would like to use yesterday. And we also have Firewire. Okay.
So, we've got a couple of questions. One is, what are the plans for MIDI as part of the MLan connection management? So, you've had enough of me. I'm going to bring up Jeff Moore now. Jeff's the engineer. Been working on the audio hardware abstraction layer, and please make him welcome. Thank you. Thank you. I like you.
My job here is to kind of delve into what the audio hardware abstraction layer is all about. So, as Bill said, it provides the lowest user level access to audio devices on the system. Its role is to efficiently move data to and from the device. It also allows you to manipulate device attributes like the volume, the sample rate, mute, whatever.
And it also provides very strong synchronization primitives to allow you to know what's going on at any given time in the hardware. The design goals that we had for the HAL, primarily the first foremost, a clean low overhead signal path. We don't want to introduce any distortion into your signal at all. And further, we want to get out of your way. We want to make sure it's getting out to the hardware as fast as it can.
Another big ticket item is multiple simultaneous client access. To single audio devices. That's been a hallmark feature of the Macintosh forever. We needed to carry that forward. And then it's to break through some of the bottlenecks we had on OS 9. You know, more channels, higher bit depths, higher sample rates. And then again, you know, synchronization. It's like, I can't say it enough.
I mean, it's like one of the most important things that we do now with audio on 10. And then finally, we came up with a pretty small API. But it's fairly complete. We think that it should cover the majority of the needs that people will have to do when trying to manipulate their audio hardware. The API itself is object-oriented C code. That's not objective C code.
But it has a Java interface as well. Since it's object-oriented, it has two major objects. It has a device object, which basically encapsulates all the information you need to know about the device. And access to the actual device. And then there's a kind of a more nebulous object, which is a global context, which allows you access to information about the system, such as, you know, the device list and whatnot.
So every object in the system has properties, and properties manipulate the different aspects of the object. Things like the name, the buffer size, volume of channel 2, whatever. You can pretty much describe anything about a device in terms of properties. The actual property itself is a unique identifier. It's a 32-bit int, and they can have an arbitrary amount of data. And there is no self-description mechanism like you get from an Apple event. The data types you get are agreed on, and they're documented in the header files.
And it's also important to know that some of the properties are only read-only. You need to make sure you're checking with the device before you try to set a property. Some devices may allow you to check with the device before you try to set a property. Some may change the sample rate. Some may not. And then finally, another big important thing about properties is that you can sign up for notifications for when things change. So if someone changes the system volume, you can find out about it.
So the global properties are all referenced using the routines in the API that use the prefix audio hardware. The constants and everything that pertain to the global context, you'll see the words audio hardware in their name somewhere. The important properties when you're looking at the global space are the device list, which is the default input and output device. And then there's a kind of a fourth property, which is whether or not you want the machine to idle sleep while you're playing sound. By default, that's disabled so that idle sleeping won't happen while you're playing sound, much like it happens on OS 9.
So here's a code example of how you would go about getting the device list. The first step is to call audio hardware get property info because the device list is documented to be a variable length array. So you need to find out what the device list is. And then you need to find out how much memory it's going to take up.
So one of the parameters you get back from audio hardware get property info is the actual size of the data. And you can see -- and then to get the number of actual devices, you divide the size you get back, which is in bytes, by the size of an audio device ID.
Then you allocate the memory to hold the list. And then you call audio hardware get property. And you pass that memory you just allocated in. And the HAL will go then and fill out all the device IDs for all the devices on the system. And then you can peruse and get information about those devices and use which devices you want that best fit your needs. And then once you have a device, all the routines, again, we use audio device to refer to the things that manipulate devices.
As you'll see, devices are addressed with a very specific protocol. You need to make sure you're asking about an input or an output property and exactly what channel you are talking about. Simple, but it's also very particular about doing things like that. The important properties that you'll see with a device are, of course, the buffer size of the device for doing the I/O transfers. An important thing to realize about that is the buffer size is not just settable by the application.
It's settable for each application individually. One application can be communicating with a device at a buffer size of, say, 64 frames, and another process could be communicating with the same device with a buffer size of 2,048 frames. It's what Bill was talking about when he was talking about controllable latency on a per-process basis. We think this is one of the big new features of audio on 10.
Then you'll also want to know things about the layout of the device, and you can use the stream configuration property to do that. Then you'll also want to know things about the volume and mute, and what data source you're talking to. They're all individual properties for the device. Here's a code example of how you would go about setting the volume of channel 2 on a device.
First thing you need to find out is if you actually can set the volume of channel 2. Again, you use Audio Device Git Property Info. You can see how I'm being very particular about specifying channel 2. I'm also making sure I'm finding out ahead of time whether or not I actually can set the property. Then when I figure it out, you just turn around and call Audio Device Set Property. In this case, the volume scaler is a floating point number from 0 to 1. In this example, we're setting the volume to full on.
So now you kind of know your way around the API a little bit. Now it's time to talk a little bit about how you actually get audio data to the hardware. We rethought how audio I/O was done to take advantage of what OS X really does well. In particular, OS X is really good at handling shared memory and threading and things that OS 9 really wasn't as good at. It's a little less good at things like hardware that has high degrees, high rates of interrupts being fired.
So we had to work around all these different constraints and come up with a system that could deliver the performance we were looking for without having to re-architect the entire kernel from the inside out. So the model we came up with is basically the hardware and the HAL that have a ring buffer that is a pretty large ring buffer. It's about 3/4 of a second in size for most drivers. And that one ring buffer is shared all across the system.
So, and the hardware tracks its progress through the ring buffer by time stamping the point at which it wraps back around. So the DMA engine is cycling through the buffer and when it jumps back around, it will generate some timing information. And that is also coincidentally the only time when you'll see a hardware interrupt.
So the hardware rate, the interrupt rate of the system has gone way down compared to OS 9. And this is much less taxing on the system. You get better throughput. The rest of the system is a lot happier. And as people are finding, audio is becoming more and more integrated in what you're doing in other parts of the system. So it's really important to be well behaved.
So to move data in and out of the ring buffer, the HAL provides what's called an I/O thread. And each device has a single I/O thread in each process in order to call your function that will provide or consume data. This thread is a Mach real-time thread. The reason why we do that is that Mach real-time threads have certain guarantees about the level of accuracy they will get for latency in scheduling. So when the HAL says this thread needs to wake up at such and such a time, because it's a Mach real-time thread, we're pretty guaranteed that it's going to wake up pretty close to when we asked it to.
And then the HAL will also use another lower priority thread in order to handle all the property notifications. And the client can actually have some degree of control over the priority. And timing characteristics of that thread using the audio hardware property run loop to tell the HAL about your own CF run loop that you want your notifications fired in.
So I'm going to walk you through kind of the algorithm of the I/O thread so you kind of have an idea of what's going on kind of behind the scenes. So the first thing that happens is when the HAL first enters the loop, the work loop of the I/O thread, is it goes to sleep.
The reason why is that it needs to prepare for input data. So presumably the hardware has just started up, and now it needs to wait for the first full buffer's worth of input data. So the very first thing it does is figure out when that's going to be, and then it puts the thread to sleep until then.
So then when it comes back and wakes up, presumably all the input data, if it's there, is available now. So it calculates what the actual timestamp is of that input data. And then it calls down into the kernel to actually fill up all the buffers out of the ring buffer. The driver itself has complete control over the transfer out of the ring buffer and into the client's buffer.
And then the same is true for output, but in this case we're about to call out to ask the client for output. So we have to figure out when we want the client, what time it is that we're asking the client for audio. And then we set up their audio buffers by clearing them out. The one thing that the HAL does is that it tries to isolate you as much as possible from other clients on the system.
So you don't have to worry about necessarily accumulating to a buffer or worrying that someone else is going to have already written data there. And then once we have the input and output data marshalled, we then call out to all the client I/O procs. And I'll talk a little bit more about writing I/O procs in a minute.
So once the I/O procs have all assembled, presumably they've consumed the input data and they provided the requested output data, the HAL will then have to call back down into the driver to mix the provided data into the system's mix bus. This is all part of the shared device management we have, and it's also the main reason why we use Float32 as our lingua franca as far as sample formats go. We want to maintain the headroom of the mix as far down and as close to the hardware as possible to minimize the amount of distortion added to the signal.
Then once we've handled the mixing, the HAL will also then handle any reentrant actions that might have occurred by calling out to the client I/O procs. For instance, you might want to adjust the buffer size on the fly to adjust your own performance. This is a very common problem with I/O procs. The HAL has a mechanism for catching those circumstances and handling it after that complete I/O cycle has completed.
[Transcript missing]
So next up, you're going to need to have an I/O proc for the I/O thread to call. So you register your I/O proc with the device, and then you have to start and stop them. You do individual transactions on starting and stopping based on the I/O proc, not on the entire device. And the reason why is that these guys are shared across the whole system.
When you register your I/O proc, the hardware may already be in use by someone else in a different process. So we manage the state relative to the I/O proc. So when you start your I/O proc, the device will only start if this is the actual first I/O proc on the entire system that is starting up on that device. And the converse is true with stopping the device.
So when your I/O proc is called, you're going to receive all the input data and you're going to be provided with a buffer in which to write all the output data for that time slice. And there are going to be timestamps that tell you exactly what's going on, where those buffers belong in the timeline. The input timestamp will tell you when the first frame of the input data was acquired. And the output timestamp will tell you when the first frame is going to be written out to the hardware.
The final timestamp is also the current time, which as you'll see from the previous diagram, falls in between. That gives you some dead reckoning on what's going on in the system. You might use that to sync other subsystems to what's going on in the hardware. So when your I/O proc is called, we pass everything in.
The data is passed into your I/O proc using an audio buffer list data structure. An audio buffer list is a collection of individual audio buffers. And you'll get a buffer for each stream that the audio device has. And you can think of a stream in this case as being a single interleaved container for the data. So a device might have two streams that have two channels in each stream.
And the audio buffer list will reflect that, that you'll receive. So what we're really trying to do is kind of mimic what the hardware is presenting to us, to you. And you can find out ahead of time what that's actually going to look like by using the stream configuration property. So that if you want to set up-- if you want to know what's going on so you can set up your blit loops or whatever, the information's there.
So this is kind of a code example of an actual I/O proc. You can see this slide has the prototype of an I/O proc. You see you get the device ID, you get all the timestamps, you get the individual audio buffer lists, and you also get a client data pointer, AKA a Refcon from OS 9. And you can use the client data pointer for anything you want. In this case, this I/O proc, I'm using the client data pointer as a pointer to my C++ object that has my audio engine in it.
So basically, you have to make sure you're-- in the I/O proc, you make sure you're checking for null. The device can change format on you between calls to your I/O proc. It can change format on you between your call to getting the format of the device and your I/O proc. The only way to be sure you know what's going on is to sign up for notifications on the format properties. But in the I/O proc, you should always make sure you're doing your sanity checks or you will crash and die horribly.
So, you can see in this case, we're basically doing all that. I passed the input buffers and the input timestamps to my engine. In this slide we see how you actually register and unregister an I/O proc. It's pretty straightforward. Add I/O proc, remove I/O proc. And you can see how I'm passing in the pointer to my engine object in this case as well.
And then starting and stopping is very much similar. There's individual calls to start and stop. and next up, I'm going to bring up Doug Wyatt. He's another engineer for Core Audio and he's going to talk a little bit about the default output unit, which is going to allow you to ignore everything I just told you about.
Thanks, Jeff. You won't have to ignore everything about it because there's some parts of the default output unit that build on top of the HAL data structures, as we'll see. I also wanted to just correct something Bill said earlier. The two sessions tomorrow, the earlier one at 3:30 is the one on the audio toolbox and audio units, and the later one at 5:00 is on MIDI. Yeah, the time's reversed. Okay, so the default output unit is a component that provides you with a slightly simpler API to the HAL. You don't have to worry about receiving quite as many notifications.
And it builds in a sample rate converter for you. So if you want to render data at 22K, you don't have to care whether the hardware is at 44K or 48K. You can just render your 22K data, say I want a sample rate converter in there, and it'll do the conversion for you.
So I'd like to just walk through a simple example of using the default output unit. It doesn't take a whole lot to write a program to generate sound this way. and David There's a call open default output unit to open the component. Audio unit initialized to initialize it.
Here we're going to manipulate the HAL device. So first we want to find out what it is. We make the call to AudioUnitGetProperty, passing the property constant, kAudioOutputUnitPropertyCurrentDevice. and David We passed the global scope. I'm not sure that's necessary, but it's the best choice. And we'll get back the audio device ID of the current device.
Here in this example, we're going to set our client's buffer size to 64 frames, which is only 1.5 milliseconds. We're going to render some audio in a very responsive manner. So we're calculating the buffer size in bytes, 64 frames times the number of channels, which is probably two, but could be more, depending on how -- we would have interrogated the stream format of the device to find out for sure.
In any case, it's 64 times the number of channels times the size of a float. And then we're making a call to the how audio device set property to change the buffer size at which this client will get called, or rather the interval at which this client will get called to render data.
Having done that, the next thing we'll do is set up a sample rate conversion. In this example, I want to render data at 22,050 hertz. I don't care what the hardware sample rate is. So there's a property on the audio unit, the default output unit, called kAudioUnit property sample rate.
Now, here the scope is important because this audio unit, if you ask it for its sample rate in the global scope, it will give you back the hardware sample rate. Whereas if you want to manipulate or interrogate the input sample rate, as you would -- in this example, you're saying I want to render at 22k. So we're telling the audio unit, yes, my input is at 22k. And so we're passing a g sample rate.
And the next step is to provide a callback function to the audio unit to tell it, here's a function in which I want to do my rendering. And this is kind of a simpler version of the HALS I/O proc, as we'll see in a moment. We fill out an audio unit input callback structure with a pointer to a function.
The refcon here is null, but it can be any piece of data that you want to access in your renderer. and David Then we make another call to AudioUnit set property with the constant KAudioUnit property set input callback, also in the global scope. And so that's telling the AudioUnit, whenever you want to render data, call me back at this function.
and here's an example of what a rendering function looks like. Like I said a moment ago, it's pretty similar to the Hal rendering function. The first parameter you get back is your RefCon. You get some flags. and David Well, we don't need to go into those. They're usually not used. You get the time stamp for output. You're getting a bus number, which is relevant when there are multiple streams of audio. And you're getting an audio buffer, which is one of the buffers that the HAL provided in its callback.
So you can look at that I/O data parameter, which is an audio buffer, and find out how many channels are in it, what the buffer size is in bytes, and from that we can compute the number of frames. We can set up a local pointer, sample pointer, as a float32, and treat that as an array into which we can fill our sample data.
That's pretty much all there is to rendering to the default output unit. After having gotten all that prepared, we can just make a call to Audio Output Unit Start. The HAL will get fired up. It will start running. Our rendering proc will start getting called back. We can synthesize sine waves or horrible noises or whatever we want.
And when we're done, we can call Audio Unit Stop -- Audio Output Unit Stop, rather. And when we're completely done, we can call Close Component to get rid of it. That's the default output unit. It's a pretty simple and high-level interface to the HAL. So this demo, I believe, is Jeff's. I'll turn it back over to you. Thanks.
So what we're going to do now is, for the very first time I think, we're going to demonstrate on an Apple operating system built-in system services for multi-channel sound output. So I'm just going to go ahead and play it and then tell you a little bit more afterwards.
[Transcript missing]
The first thing I want to do is kind of show you what we're using here. This is a stock Wall Street PowerBook running OS X with a USB PC card attached to it. This is the eMagic EMI26. Thank you, eMagic. And this is on sale today. And it's using our stock built-in USB audio class driver.
This is all built into the system. It's great. A couple other things I want to show you about this little test app here. This little test app is in the /developer/examples/core-audio directory. It was written by one of our other engineers, Bob Aaron, to kind of demonstrate what's going on in the how and kind of where everything's at.
It kind of gives you a user interface for all the different little properties you'll see in the header files. In particular, you'll see it shows the buffer size in bytes and in frames. It shows you all the format information that you might have for the device. It allows you to change the format.
And then it gives you individual controls over the hardware for as long as the hardware has it implemented. You notice in this case that this device only has a master output volume and a master mute. So you can see it now. I'll switch to the built-in output device.
And you can see it has two left/right control, individual channel controls, and no master. But it does still have a master mute. The how does not abstract this away from you. If you're looking for a master control, it may not be there. You need to be prepared for that.
The how is not going to hide what's going on in the hardware from you too much. Obviously, it's going to abstract a little bit of stuff away from you, obviously the sample format being one of them. You can see that there's a whole lot in here. And I encourage you to go and build this code example yourself and play with it.
And those of you bringing up hardware, this is a great test tool to figure out if you're doing everything right. So I think I'll play that again, kind of give you-- the track I'm playing here is a 5.1 mix. It's a six-channel AIFF file that I authored last week. So I think I'm just going to go ahead and play it again. Turn the volume down.
[Transcript missing]
The app is called Daisy and you have the source code. It's already installed in your system if you install the developer tools. I think that's pretty much it. Can we go back to the slides please? Next, Bill is going to come up and tell you more about Java.
So we'll be doing some Q&A and stuff in a minute, so don't all rush off unless you want to get to the beer bust, but we won't keep you too much longer. I hate to keep a man from his beer. So I don't actually have any examples today that I want to show you about the Cordia Java stuff. I do have some stuff tomorrow that I'll go through.
The audio hardware and the audio device stuff is in core audio Java. It's in actually a com.apple.audio.hardware package. You'll see the same kinds of APIs that Jeff has talk about, start, stop. You've got audio device, IOProc is a Java interface. You implement that interface and then you instantiate that interface as your call back in order to render data for the audio device IOProc.
The default output audio unit is there as well. One thing I'd like to add to those comments is that that will, the reason the default output unit is there is to track choices that the user might make in the system control panel when the system control panel will let you make choices, which it currently doesn't. So you might imagine that you could have a user that might have two or three different audio devices on their system and they would like to say, well, my, you know, default output device, will be the USB guy, it will be built in audio.
And the default output unit will listen for those things and it will switch automatically for you. So your application, if you're just doing basic audio stuff, this becomes a very useful service at the bottom and it's the same kind of service that the sound manager itself sits on top of.
The default output unit is actually an extension of something we call a HAL output unit. So if you're writing audio units or you're using audio units to do your application, you can use a HAL output unit just to talk to a particular device or you can use this guy if you want to track any changes the user might make to their system. And as Doug said, he showed you setting the sample rate, you can also not have it do the sample rate conversion if you want to take care of that detail yourself. It's not a requirement that it does that for you.
With the Cordia Java stuff, there's Java doc that's available. And I'll give you some URLs at the end of this talk for that sign of stuff. Regardless of the language that you use, we're really not sort of language centric in the Corio group, because I'm there I suppose more than anything else, otherwise it would all be C++.
So we really kind of stress that you should understand the architecture, whether you're going to approach dealing with the API through C or C++ or through Java, you really need to understand the architecture of how the system is working. You need to understand the underpinnings of the system and these are really not language constructs, they're architectural constructs that you should do.
So when we talk about an API for the Java platform, we're not talking about any additional capability. We haven't rewritten this whole thing in Java, it's not going to be portable because it's based on a native audio engine, but we're just providing an access to it from Java.
So some of the stuff that you see today, if you go home on your Mac OS X system now and you run DAISY, you'll see it looks a little bit different than the version that we're running. We've done additional work since Mac OS X was released in order to support the USB stuff that we were showing today.
And we are very interested in doing technology. Obviously we're going to release this stuff to the broader community as soon as we can. I just don't want you to sort of get a false expectation of going home and trying it doesn't work and then you're going to abuse me. So you can contact us.
I'll give you an email at the end of the talk today about contacting us if you're interested in getting technology seeding from us. And of course, you know, we're close to releasing this to the general public as well. So another thing that we're sort of announcing today is we have a mailing list up. Apple sponsors a website called list.apple.com.
These are not really Apple's, Apple run lists or anything. They're really a service to Apple developers and the Apple community that's basically there. You can get it from Apple. But these aren't sort of like, I suppose they are in some way official Apple mailing lists. But they're not official Apple mailing lists. They're your mailing lists. They're not censored or monitored by people at Apple. They're really, it's your resource that you can use. You can support each other with it. We obviously like to be involved in these things.
And we do now have a core audio mailing list. And I'm pleased about it. And you can get there at list.apple.com and you'll see the core audio list. And we'll field any questions there on Java, core audio stuff, on the MIDI stuff, on the things that we'll cover tomorrow in the talks. And also today we have a website up that actually talks about Mac OS X audio for the first time. And it's developer.apple.com/audio. Okay.
And we're also this close to documentation. We realize it's been a very, very frustrating experience for us and probably for you about, well, this stuff is there but how do you know about it because we're not telling anybody about it. It's sort of a best kept secret. But up on the audio website there will be a PDF.
It's a draft only of the core audio APIs. And we're doing more work and we'll update that in the future. If that's not available by tomorrow, then it will be available early next week. And it's a pretty good sort of first pass. And we're also on the mailing list so if you get the documentation, you've got SDK examples and we're more than happy to answer questions and help you with problems or listen to your feedback. So we really welcome your input.
Ok, there's a sound networking for games session tomorrow, and then they're the two times of the sessions, and they're the right times, not the wrong times. I'll come back to this slide probably. Ok, so if you've got any questions on Firewire or USB, as Craig said earlier, this is stuff that we're fairly involved in with the audio community. So, you can contact Craig at that address and develop a seating, which I talked about earlier. You can send us an email and we will certainly consider your request.