Don't include alu.h in alMain.h
[openal-soft.git] / Alc / backends / coreaudio.c
blob69a7404a42790f089244ba8b716f4ab6c3433d34
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "alMain.h"
28 #include "alu.h"
30 #include <CoreServices/CoreServices.h>
31 #include <unistd.h>
32 #include <AudioUnit/AudioUnit.h>
33 #include <AudioToolbox/AudioToolbox.h>
36 typedef struct {
37 AudioUnit audioUnit;
39 ALuint frameSize;
40 ALdouble sampleRateRatio; // Ratio of hardware sample rate / requested sample rate
41 AudioStreamBasicDescription format; // This is the OpenAL format as a CoreAudio ASBD
43 AudioConverterRef audioConverter; // Sample rate converter if needed
44 AudioBufferList *bufferList; // Buffer for data coming from the input device
45 ALCvoid *resampleBuffer; // Buffer for returned RingBuffer data when resampling
47 RingBuffer *ring;
48 } ca_data;
50 static const ALCchar ca_device[] = "CoreAudio Default";
53 static void destroy_buffer_list(AudioBufferList* list)
55 if(list)
57 UInt32 i;
58 for(i = 0;i < list->mNumberBuffers;i++)
59 free(list->mBuffers[i].mData);
60 free(list);
64 static AudioBufferList* allocate_buffer_list(UInt32 channelCount, UInt32 byteSize)
66 AudioBufferList *list;
68 list = calloc(1, sizeof(AudioBufferList) + sizeof(AudioBuffer));
69 if(list)
71 list->mNumberBuffers = 1;
73 list->mBuffers[0].mNumberChannels = channelCount;
74 list->mBuffers[0].mDataByteSize = byteSize;
75 list->mBuffers[0].mData = malloc(byteSize);
76 if(list->mBuffers[0].mData == NULL)
78 free(list);
79 list = NULL;
82 return list;
85 static OSStatus ca_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp,
86 UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
88 ALCdevice *device = (ALCdevice*)inRefCon;
89 ca_data *data = (ca_data*)device->ExtraData;
91 aluMixData(device, ioData->mBuffers[0].mData,
92 ioData->mBuffers[0].mDataByteSize / data->frameSize);
94 return noErr;
97 static OSStatus ca_capture_conversion_callback(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets,
98 AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void* inUserData)
100 ALCdevice *device = (ALCdevice*)inUserData;
101 ca_data *data = (ca_data*)device->ExtraData;
103 // Read from the ring buffer and store temporarily in a large buffer
104 ReadRingBuffer(data->ring, data->resampleBuffer, (ALsizei)(*ioNumberDataPackets));
106 // Set the input data
107 ioData->mNumberBuffers = 1;
108 ioData->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame;
109 ioData->mBuffers[0].mData = data->resampleBuffer;
110 ioData->mBuffers[0].mDataByteSize = (*ioNumberDataPackets) * data->format.mBytesPerFrame;
112 return noErr;
115 static OSStatus ca_capture_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
116 const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
117 UInt32 inNumberFrames, AudioBufferList *ioData)
119 ALCdevice *device = (ALCdevice*)inRefCon;
120 ca_data *data = (ca_data*)device->ExtraData;
121 AudioUnitRenderActionFlags flags = 0;
122 OSStatus err;
124 // fill the bufferList with data from the input device
125 err = AudioUnitRender(data->audioUnit, &flags, inTimeStamp, 1, inNumberFrames, data->bufferList);
126 if(err != noErr)
128 ERR("AudioUnitRender error: %d\n", err);
129 return err;
132 WriteRingBuffer(data->ring, data->bufferList->mBuffers[0].mData, inNumberFrames);
134 return noErr;
137 static ALCenum ca_open_playback(ALCdevice *device, const ALCchar *deviceName)
139 ComponentDescription desc;
140 Component comp;
141 ca_data *data;
142 OSStatus err;
144 if(!deviceName)
145 deviceName = ca_device;
146 else if(strcmp(deviceName, ca_device) != 0)
147 return ALC_INVALID_VALUE;
149 /* open the default output unit */
150 desc.componentType = kAudioUnitType_Output;
151 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
152 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
153 desc.componentFlags = 0;
154 desc.componentFlagsMask = 0;
156 comp = FindNextComponent(NULL, &desc);
157 if(comp == NULL)
159 ERR("FindNextComponent failed\n");
160 return ALC_INVALID_VALUE;
163 data = calloc(1, sizeof(*data));
165 err = OpenAComponent(comp, &data->audioUnit);
166 if(err != noErr)
168 ERR("OpenAComponent failed\n");
169 free(data);
170 return ALC_INVALID_VALUE;
173 /* init and start the default audio unit... */
174 err = AudioUnitInitialize(data->audioUnit);
175 if(err != noErr)
177 ERR("AudioUnitInitialize failed\n");
178 CloseComponent(data->audioUnit);
179 free(data);
180 return ALC_INVALID_VALUE;
183 device->DeviceName = strdup(deviceName);
184 device->ExtraData = data;
185 return ALC_NO_ERROR;
188 static void ca_close_playback(ALCdevice *device)
190 ca_data *data = (ca_data*)device->ExtraData;
192 AudioUnitUninitialize(data->audioUnit);
193 CloseComponent(data->audioUnit);
195 free(data);
196 device->ExtraData = NULL;
199 static ALCboolean ca_reset_playback(ALCdevice *device)
201 ca_data *data = (ca_data*)device->ExtraData;
202 AudioStreamBasicDescription streamFormat;
203 AURenderCallbackStruct input;
204 OSStatus err;
205 UInt32 size;
207 err = AudioUnitUninitialize(data->audioUnit);
208 if(err != noErr)
209 ERR("-- AudioUnitUninitialize failed.\n");
211 /* retrieve default output unit's properties (output side) */
212 size = sizeof(AudioStreamBasicDescription);
213 err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, &size);
214 if(err != noErr || size != sizeof(AudioStreamBasicDescription))
216 ERR("AudioUnitGetProperty failed\n");
217 return ALC_FALSE;
220 #if 0
221 TRACE("Output streamFormat of default output unit -\n");
222 TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
223 TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
224 TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
225 TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
226 TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
227 TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
228 #endif
230 /* set default output unit's input side to match output side */
231 err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, size);
232 if(err != noErr)
234 ERR("AudioUnitSetProperty failed\n");
235 return ALC_FALSE;
238 if(device->Frequency != streamFormat.mSampleRate)
240 device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize *
241 streamFormat.mSampleRate /
242 device->Frequency);
243 device->Frequency = streamFormat.mSampleRate;
246 /* FIXME: How to tell what channels are what in the output device, and how
247 * to specify what we're giving? eg, 6.0 vs 5.1 */
248 switch(streamFormat.mChannelsPerFrame)
250 case 1:
251 device->FmtChans = DevFmtMono;
252 break;
253 case 2:
254 device->FmtChans = DevFmtStereo;
255 break;
256 case 4:
257 device->FmtChans = DevFmtQuad;
258 break;
259 case 6:
260 device->FmtChans = DevFmtX51;
261 break;
262 case 7:
263 device->FmtChans = DevFmtX61;
264 break;
265 case 8:
266 device->FmtChans = DevFmtX71;
267 break;
268 default:
269 ERR("Unhandled channel count (%d), using Stereo\n", streamFormat.mChannelsPerFrame);
270 device->FmtChans = DevFmtStereo;
271 streamFormat.mChannelsPerFrame = 2;
272 break;
274 SetDefaultWFXChannelOrder(device);
276 /* use channel count and sample rate from the default output unit's current
277 * parameters, but reset everything else */
278 streamFormat.mFramesPerPacket = 1;
279 switch(device->FmtType)
281 case DevFmtUByte:
282 device->FmtType = DevFmtByte;
283 /* fall-through */
284 case DevFmtByte:
285 streamFormat.mBitsPerChannel = 8;
286 streamFormat.mBytesPerPacket = streamFormat.mChannelsPerFrame;
287 streamFormat.mBytesPerFrame = streamFormat.mChannelsPerFrame;
288 break;
289 case DevFmtUShort:
290 case DevFmtFloat:
291 device->FmtType = DevFmtShort;
292 /* fall-through */
293 case DevFmtShort:
294 streamFormat.mBitsPerChannel = 16;
295 streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
296 streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
297 break;
298 case DevFmtUInt:
299 device->FmtType = DevFmtInt;
300 /* fall-through */
301 case DevFmtInt:
302 streamFormat.mBitsPerChannel = 32;
303 streamFormat.mBytesPerPacket = 2 * streamFormat.mChannelsPerFrame;
304 streamFormat.mBytesPerFrame = 2 * streamFormat.mChannelsPerFrame;
305 break;
307 streamFormat.mFormatID = kAudioFormatLinearPCM;
308 streamFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
309 kAudioFormatFlagsNativeEndian |
310 kLinearPCMFormatFlagIsPacked;
312 err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(AudioStreamBasicDescription));
313 if(err != noErr)
315 ERR("AudioUnitSetProperty failed\n");
316 return ALC_FALSE;
319 /* setup callback */
320 data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
321 input.inputProc = ca_callback;
322 input.inputProcRefCon = device;
324 err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(AURenderCallbackStruct));
325 if(err != noErr)
327 ERR("AudioUnitSetProperty failed\n");
328 return ALC_FALSE;
331 /* init the default audio unit... */
332 err = AudioUnitInitialize(data->audioUnit);
333 if(err != noErr)
335 ERR("AudioUnitInitialize failed\n");
336 return ALC_FALSE;
339 return ALC_TRUE;
342 static ALCboolean ca_start_playback(ALCdevice *device)
344 ca_data *data = (ca_data*)device->ExtraData;
345 OSStatus err;
347 err = AudioOutputUnitStart(data->audioUnit);
348 if(err != noErr)
350 ERR("AudioOutputUnitStart failed\n");
351 return ALC_FALSE;
354 return ALC_TRUE;
357 static void ca_stop_playback(ALCdevice *device)
359 ca_data *data = (ca_data*)device->ExtraData;
360 OSStatus err;
362 err = AudioOutputUnitStop(data->audioUnit);
363 if(err != noErr)
364 ERR("AudioOutputUnitStop failed\n");
367 static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName)
369 AudioStreamBasicDescription requestedFormat; // The application requested format
370 AudioStreamBasicDescription hardwareFormat; // The hardware format
371 AudioStreamBasicDescription outputFormat; // The AudioUnit output format
372 AURenderCallbackStruct input;
373 ComponentDescription desc;
374 AudioDeviceID inputDevice;
375 UInt32 outputFrameCount;
376 UInt32 propertySize;
377 UInt32 enableIO;
378 Component comp;
379 ca_data *data;
380 OSStatus err;
382 desc.componentType = kAudioUnitType_Output;
383 desc.componentSubType = kAudioUnitSubType_HALOutput;
384 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
385 desc.componentFlags = 0;
386 desc.componentFlagsMask = 0;
388 // Search for component with given description
389 comp = FindNextComponent(NULL, &desc);
390 if(comp == NULL)
392 ERR("FindNextComponent failed\n");
393 return ALC_INVALID_VALUE;
396 data = calloc(1, sizeof(*data));
397 device->ExtraData = data;
399 // Open the component
400 err = OpenAComponent(comp, &data->audioUnit);
401 if(err != noErr)
403 ERR("OpenAComponent failed\n");
404 goto error;
407 // Turn off AudioUnit output
408 enableIO = 0;
409 err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(ALuint));
410 if(err != noErr)
412 ERR("AudioUnitSetProperty failed\n");
413 goto error;
416 // Turn on AudioUnit input
417 enableIO = 1;
418 err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(ALuint));
419 if(err != noErr)
421 ERR("AudioUnitSetProperty failed\n");
422 goto error;
425 // Get the default input device
426 propertySize = sizeof(AudioDeviceID);
427 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize, &inputDevice);
428 if(err != noErr)
430 ERR("AudioHardwareGetProperty failed\n");
431 goto error;
434 if(inputDevice == kAudioDeviceUnknown)
436 ERR("No input device found\n");
437 goto error;
440 // Track the input device
441 err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &inputDevice, sizeof(AudioDeviceID));
442 if(err != noErr)
444 ERR("AudioUnitSetProperty failed\n");
445 goto error;
448 // set capture callback
449 input.inputProc = ca_capture_callback;
450 input.inputProcRefCon = device;
452 err = AudioUnitSetProperty(data->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &input, sizeof(AURenderCallbackStruct));
453 if(err != noErr)
455 ERR("AudioUnitSetProperty failed\n");
456 goto error;
459 // Initialize the device
460 err = AudioUnitInitialize(data->audioUnit);
461 if(err != noErr)
463 ERR("AudioUnitInitialize failed\n");
464 goto error;
467 // Get the hardware format
468 propertySize = sizeof(AudioStreamBasicDescription);
469 err = AudioUnitGetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &hardwareFormat, &propertySize);
470 if(err != noErr || propertySize != sizeof(AudioStreamBasicDescription))
472 ERR("AudioUnitGetProperty failed\n");
473 goto error;
476 // Set up the requested format description
477 switch(device->FmtType)
479 case DevFmtUByte:
480 requestedFormat.mBitsPerChannel = 8;
481 requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
482 break;
483 case DevFmtShort:
484 requestedFormat.mBitsPerChannel = 16;
485 requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
486 break;
487 case DevFmtInt:
488 requestedFormat.mBitsPerChannel = 32;
489 requestedFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
490 break;
491 case DevFmtFloat:
492 requestedFormat.mBitsPerChannel = 32;
493 requestedFormat.mFormatFlags = kAudioFormatFlagIsPacked;
494 break;
495 case DevFmtByte:
496 case DevFmtUShort:
497 case DevFmtUInt:
498 ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType));
499 goto error;
502 switch(device->FmtChans)
504 case DevFmtMono:
505 requestedFormat.mChannelsPerFrame = 1;
506 break;
507 case DevFmtStereo:
508 requestedFormat.mChannelsPerFrame = 2;
509 break;
511 case DevFmtQuad:
512 case DevFmtX51:
513 case DevFmtX51Side:
514 case DevFmtX61:
515 case DevFmtX71:
516 ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans));
517 goto error;
520 requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
521 requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
522 requestedFormat.mSampleRate = device->Frequency;
523 requestedFormat.mFormatID = kAudioFormatLinearPCM;
524 requestedFormat.mReserved = 0;
525 requestedFormat.mFramesPerPacket = 1;
527 // save requested format description for later use
528 data->format = requestedFormat;
529 data->frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
531 // Use intermediate format for sample rate conversion (outputFormat)
532 // Set sample rate to the same as hardware for resampling later
533 outputFormat = requestedFormat;
534 outputFormat.mSampleRate = hardwareFormat.mSampleRate;
536 // Determine sample rate ratio for resampling
537 data->sampleRateRatio = outputFormat.mSampleRate / device->Frequency;
539 // The output format should be the requested format, but using the hardware sample rate
540 // This is because the AudioUnit will automatically scale other properties, except for sample rate
541 err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, (void *)&outputFormat, sizeof(outputFormat));
542 if(err != noErr)
544 ERR("AudioUnitSetProperty failed\n");
545 goto error;
548 // Set the AudioUnit output format frame count
549 outputFrameCount = device->UpdateSize * data->sampleRateRatio;
550 err = AudioUnitSetProperty(data->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Output, 0, &outputFrameCount, sizeof(outputFrameCount));
551 if(err != noErr)
553 ERR("AudioUnitSetProperty failed: %d\n", err);
554 goto error;
557 // Set up sample converter
558 err = AudioConverterNew(&outputFormat, &requestedFormat, &data->audioConverter);
559 if(err != noErr)
561 ERR("AudioConverterNew failed: %d\n", err);
562 goto error;
565 // Create a buffer for use in the resample callback
566 data->resampleBuffer = malloc(device->UpdateSize * data->frameSize * data->sampleRateRatio);
568 // Allocate buffer for the AudioUnit output
569 data->bufferList = allocate_buffer_list(outputFormat.mChannelsPerFrame, device->UpdateSize * data->frameSize * data->sampleRateRatio);
570 if(data->bufferList == NULL)
571 goto error;
573 data->ring = CreateRingBuffer(data->frameSize, (device->UpdateSize * data->sampleRateRatio) * device->NumUpdates);
574 if(data->ring == NULL)
575 goto error;
577 return ALC_NO_ERROR;
579 error:
580 DestroyRingBuffer(data->ring);
581 free(data->resampleBuffer);
582 destroy_buffer_list(data->bufferList);
584 if(data->audioConverter)
585 AudioConverterDispose(data->audioConverter);
586 if(data->audioUnit)
587 CloseComponent(data->audioUnit);
589 free(data);
590 device->ExtraData = NULL;
592 return ALC_INVALID_VALUE;
595 static void ca_close_capture(ALCdevice *device)
597 ca_data *data = (ca_data*)device->ExtraData;
599 DestroyRingBuffer(data->ring);
600 free(data->resampleBuffer);
601 destroy_buffer_list(data->bufferList);
603 AudioConverterDispose(data->audioConverter);
604 CloseComponent(data->audioUnit);
606 free(data);
607 device->ExtraData = NULL;
610 static void ca_start_capture(ALCdevice *device)
612 ca_data *data = (ca_data*)device->ExtraData;
613 OSStatus err = AudioOutputUnitStart(data->audioUnit);
614 if(err != noErr)
615 ERR("AudioOutputUnitStart failed\n");
618 static void ca_stop_capture(ALCdevice *device)
620 ca_data *data = (ca_data*)device->ExtraData;
621 OSStatus err = AudioOutputUnitStop(data->audioUnit);
622 if(err != noErr)
623 ERR("AudioOutputUnitStop failed\n");
626 static ALCenum ca_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
628 ca_data *data = (ca_data*)device->ExtraData;
629 AudioBufferList *list;
630 UInt32 frameCount;
631 OSStatus err;
633 // If no samples are requested, just return
634 if(samples == 0)
635 return ALC_NO_ERROR;
637 // Allocate a temporary AudioBufferList to use as the return resamples data
638 list = alloca(sizeof(AudioBufferList) + sizeof(AudioBuffer));
640 // Point the resampling buffer to the capture buffer
641 list->mNumberBuffers = 1;
642 list->mBuffers[0].mNumberChannels = data->format.mChannelsPerFrame;
643 list->mBuffers[0].mDataByteSize = samples * data->frameSize;
644 list->mBuffers[0].mData = buffer;
646 // Resample into another AudioBufferList
647 frameCount = samples;
648 err = AudioConverterFillComplexBuffer(data->audioConverter, ca_capture_conversion_callback,
649 device, &frameCount, list, NULL);
650 if(err != noErr)
652 ERR("AudioConverterFillComplexBuffer error: %d\n", err);
653 return ALC_INVALID_VALUE;
655 return ALC_NO_ERROR;
658 static ALCuint ca_available_samples(ALCdevice *device)
660 ca_data *data = device->ExtraData;
661 return RingBufferSize(data->ring) / data->sampleRateRatio;
665 static const BackendFuncs ca_funcs = {
666 ca_open_playback,
667 ca_close_playback,
668 ca_reset_playback,
669 ca_start_playback,
670 ca_stop_playback,
671 ca_open_capture,
672 ca_close_capture,
673 ca_start_capture,
674 ca_stop_capture,
675 ca_capture_samples,
676 ca_available_samples,
677 ALCdevice_LockDefault,
678 ALCdevice_UnlockDefault,
679 ALCdevice_GetLatencyDefault
682 ALCboolean alc_ca_init(BackendFuncs *func_list)
684 *func_list = ca_funcs;
685 return ALC_TRUE;
688 void alc_ca_deinit(void)
692 void alc_ca_probe(enum DevProbe type)
694 switch(type)
696 case ALL_DEVICE_PROBE:
697 AppendAllDevicesList(ca_device);
698 break;
699 case CAPTURE_DEVICE_PROBE:
700 AppendCaptureDeviceList(ca_device);
701 break;