- Sound Devices
사운드 장치(Sound Devices)
To write a driver for a sound device, create a subclass of IOAudio. See the IOAudio Class description for additional information on writing a driver.
Directories in /NextDeveloper/Examples/DriverKit with examples of sound drivers include ProAudioSpectrum16 and SoundBlaster8.
The following hardware is required or recommended for development and support efforts:
- At least one workstation with NEXTSTEP User and Developer software
- A second NEXTSTEP workstation (optional, but recommended. One can serve as debug master, the other slave. This allows source debugging of the loaded driver.)
- Sound card
- Microphone, headphones or amplifier, and speakers that are all known to work with the sound card
- Logic analyzer
Here are the basic operations needed for an audio driver:
- Instantiating and initializing a driver object
- Starting and stopping data transfers
- Handling interrupts
- Determining supported features
- Changing hardware settings such as volume
Instantiating and Initializing a Driver Object
Override probe: to allocate an instance of the driver and initialize it by invoking IOAudio's initFromDeviceDescription: method.
Override initFromDeviceDescription: method and invoke super's implementation. IOAudio's initFromDeviceDescription: method invokes the reset method, which you must implement to check whether hardware is present. If hardware is present, the method should set it to a known state. It should also configure the host DMA channel to auto initialize mode if the sound card supports it. (Otherwise, you'll have to restart the DMA transfer every time you handle an interrupt.) It should return nil if the hardware isn't present.
If initFromDeviceDescription: returns nil, probe: shouldn't allocate a driver instance and should return NO.
Starting and Stopping Data Transfers
Override IOAudio's startDMAForchannel:read:buffer:bufferSizeForInterrupts: method in your driver. Your method should do the following:
- Configure your audio hardware to use the selected sample rate, data encoding, and channel count.
- Set audio hardware to auto initialize mode, if possible.
- Start the audio hardware's data transfer engine.
- Enable interrupts and start the host master DMA.
- Invoke IODirectDevice's startDMAForBuffer:channel: (part of the kernel), which you've configured to start the DMA on a selected channel.
Note: startDMAForchannel:read:buffer:bufferSizeForInterrupts: must be called only from the I/O thread.
Override IOAudio's stopDMAForChannel:read: method in your subclass to perform these operations:
- Disable interrupts.
- Turn off the DMA channel.
- Stop any data transfer from the audio hardware.
The Driver Kit already implements an interrupt handler for sound. You must implement the method interruptOccurredForInput:forOutput: to take these actions:
- Determine which, if any, channel interrupted and perform the necessary actions to acknowledge the interrupt.
- Return BOOL values in each of the method's two BOOL parameters: YES if there is data in the corresponding channel and NO otherwise.
Note: The interruptOccurredForInput:forOutput: method must be called only from the I/O thread.
Write a function that clears audio hardware interrupts and implement interruptClearFunc to return the address of this function. This function is called by the interrupt handler when there's an audio interrupt, so it can't block.
Determining Supported Features
Implement the following methods to provide the following feature information:
- acceptsContinuousSamplingRates to return whether continuous sampling rates is supported
- channelCountLimit to return 1 for mono or 2 for stereo
- getDataEncodings:count: to return an array of supported data encodings
- getInputChannelBuffer:size: to return the input channel's buffer address and size
- getOuputChannelBuffer:size: to return the output channel's buffer address and size
- getSamplingRates:count: to return supported sampling rates in an array and a count of the number of rates supported
- getSamplingRatesLow:high: to return the lowest and highest sampling rates supported
Setting Hardware State
The user can set various audio parameters. IOAudio has a set of methods that return the values set by the user. You implement an accompanying set of methods to convert these user values to values your hardware understands by scaling the values appropriately and updating the hardware state to the scaled values. Implement the methods if the audio hardware supports the corresponding features. IOAudio provides the following methods to get the user value and update the associated hardware state:
- inputGainLeft and updateInputGainLeft
- inputGainRight and updateInputGainRight
- isLoudnessEnhanced and updateLoudnessEnhanced
- isOutputMuted and updateOutputMute
- outputAttenuationLeft and updateOutputAttenuationLeft
- outputAttenuationRight and updateOutputAttenuationRight
Input gain runs from 0 (no sound) to 32767 (maximum); attenuation goes from 84 (no sound) to 0 (maximum).
Note: IOAudio invokes all the update... methods from the I/O thread.
IOAudio's support for audio drivers has the following limitation you should know about:
- You can't override the methods (dataEncoding and getDataEncodings:count:, for example) that interpret NXSoundParameterTags passed from user-level programs. Consequently, you have to use some other way to provide support for device-specific features such as on-board compression.
Suggestions for Development
If the audio hardware supports a superset of a well-known interface, consider developing it first. It's even better if a template is available. Then add features specific to your audio hardware.
When you start debugging, first try to get an interrupt. When you do, you know data transfers are occurring.
As a debugging aid, consider writing a user-level program to use IODeviceMaster to read and write ports.