Important: Inside Macintosh: Sound is deprecated as of Mac OS X v10.5. For new audio development in Mac OS X, use Core Audio. See the Audio page in the ADC Reference Library.
Dispatching to Sound Component-Defined Routines
As explained earlier, the code stored in the sound component should be contained in a resource of typekSoundComponentCodeType
. The Component Manager expects the entry point in this resource to be a function with this format:
pascal ComponentResult MySurfDispatch (ComponentParameters *params, SoundComponentGlobalsPtr globals);The Component Manager calls your sound component by passingMySurfDispatch
a selector in theparams->what
field;MySurfDispatch
must interpret the selector and possibly dispatch to some other routine in the resource. Your sound component must be able to handle the required selectors, defined by these constants:
#define kComponentOpenSelect -1 #define kComponentCloseSelect -2 #define kComponentCanDoSelect -3 #define kComponentVersionSelect -4 #define kComponentRegisterSelect -5 #define kComponentTargetSelect -6 #define kComponentUnregisterSelect -7In addition, your sound component must be able to respond to component-specific selectors. Some of these selectors must be handled by your component; if your component doesn't implement one of these selectors, it should return the badComponentSelector result code. Other selectors should be delegated up the component chain. This allows the Sound Manager to query a particular component chain by passing a selector to the first component in the chain. If your component does not implement a delegable selector, it should call the Component Manager routine DelegateComponentCall to delegate the selector to its source component. If your sound component does implement a particular delegable selector, it should perform the operation associated with it. The Sound Manager defines a constant to designate the delegable selectors.
- Note
- For complete details on required component selectors, see the chapter "Component Manager" in Inside Macintosh: More Macintosh Toolbox.
/*first selector that can be delegated up the chain*/ #define kDelegatedSoundComponentSelectors 0x0100The Sound Manager can pass these selectors to your sound component:
enum { /*the following calls cannot be delegated*/ kSoundComponentInitOutputDeviceSelect = 1, kSoundComponentSetSourceSelect, kSoundComponentGetSourceSelect, kSoundComponentGetSourceDataSelect, kSoundComponentSetOutputSelect, /*the following calls can be delegated*/ kSoundComponentAddSourceSelect = kDelegatedSoundComponentSelectors + 1, kSoundComponentRemoveSourceSelect, kSoundComponentGetInfoSelect, kSoundComponentSetInfoSelect, kSoundComponentStartSourceSelect, kSoundComponentStopSourceSelect, kSoundComponentPauseSourceSelect, kSoundComponentPlaySourceBufferSelect };You can respond to these selectors by calling the Component Manager routineCallComponentFunctionWithStorage
or by delegating the selector to your component's source component. Listing 5-2 illustrates how to define a sound component entry point routine.Listing 5-2 Handling Component Manager selectors
pascal ComponentResult MySurfDispatch (ComponentParameters *params, SoundComponentGlobalsPtr globals) { ComponentRoutine myRoutine; ComponentResult myResult; /*Get address of component-defined routine.*/ myRoutine = MyGetComponentRoutine(params->what); if (myRoutine == nil) /*selector not implemented*/ myResult = badComponentSelector; else if (myRoutine == kDelegateCall) /*selector should be delegated*/ myResult = DelegateComponentCall(params, globals->sourceComponent); else myResult = CallComponentFunctionWithStorage((Handle) globals, params, (ComponentRoutine) myRoutine); return (myResult); }As you can see, theMySurfDispatch
function defined in Listing 5-2 simply retrieves the address of the appropriate component-defined routine, as determined by theparams->what
field. If the routineMyGetComponentRoutine
returnsnil
, thenMySurfDispatch
itself returns thebadComponentSelector
result code. Otherwise, if the selector should be delegated,MySurfDispatch
callsDelegateComponentCall
to do so. Finally, if the selector hasn't yet been handled, the appropriate component-defined routine is executed viaCallComponentFunctionWithStorage
.Listing 5-3 defines the function
MyGetComponentRoutine
.Listing 5-3 Finding the address of a component-defined routine
ComponentRoutine MyGetComponentRoutine (short selector) { void *myRoutine; if (selector < 0) switch (selector) /*required component selectors*/ { case kComponentRegisterSelect: myRoutine = MyRegisterSoundComponent; break; case kComponentVersionSelect: myRoutine = MySoundComponentVersion; break; case kComponentCanDoSelect: myRoutine = MySoundComponentCanDo; break; case kComponentCloseSelect: myRoutine = MyCloseSoundComponent; break; case kComponentOpenSelect: myRoutine = MyOpenSoundComponent; break; default: myRoutine = nil; /*unknown selector, so fail*/ break; } else if (selector < kDelegatedSoundComponentSelectors) /*selectors that can't be delegated*/ switch (selector) { case kSoundComponentInitOutputDeviceSelect: myRoutine = MySoundComponentInitOutputDevice; break; case kSoundComponentSetSourceSelect: case kSoundComponentGetSourceSelect: case kSoundComponentGetSourceDataSelect: case kSoundComponentSetOutputSelect: default: myRoutine = nil; /*unknown selector, so fail*/ break; } else /*selectors that can be delegated*/ switch (selector) { case kSoundComponentStartSourceSelect: myRoutine = MySoundComponentStartSource; break; case kSoundComponentPlaySourceBufferSelect: myRoutine = MySoundComponentPlaySourceBuffer; break; case kSoundComponentGetInfoSelect: myRoutine = MySoundComponentGetInfo; break; case kSoundComponentSetInfoSelect: myRoutine = MySoundComponentSetInfo; break; case kSoundComponentAddSourceSelect: case kSoundComponentRemoveSourceSelect: case kSoundComponentStopSourceSelect: case kSoundComponentPauseSourceSelect: default: myRoutine = kDelegateCall; /*delegate it*/ break; } return (myRoutine); }In all likelihood, your component is loaded into the system heap, although it might be loaded into an application heap if memory is low in the system heap. You can call the Component Manager function GetComponentInstanceA5 to determine the A5 value of the current application. If this function returns 0, your component is in the system heap; otherwise, your component is in an application's heap. Its location might affect how you allocate memory. For example, calling the MoveHHi routine on handles in the system heap has no result. Thus, you should either call the ReserveMemSys routine before calling NewHandleSys (so that the handle is allocated as low in the system heap as possible) or else just allocate a nonrelocatable block by calling theNewPtrSys
routine.If you need to access resources that are stored in your sound component, you can use
OpenComponentResFile
andCloseComponentResFile
.OpenComponentResFile
requires theComponentInstance
parameter supplied to your routine. You should not call Resource Manager routines such asOpenResFile
orCloseResFile
.
The following sections illustrate how to define some of the sound component functions.
- WARNING
- Do not leave any resource files open when your sound component is closed. Their maps will be left in the subheap when the subheap is freed, causing the Resource Manager to crash.