397 return TRUE;
398 }
399
400
401 // counts number of valid (non-NULL) elements in the array of AudioControls
402 static int ValidControlCount(AudioControl **arr, int offset, int len) {
403 int result = 0;
404 int end = offset + len;
405 for (int i=offset; i<end; i++) {
406 if (arr[i] != NULL)
407 result++;
408 }
409 return result;
410 }
411
412 // returns java control
413 static void* CreatePortControl(PortMixer *mixer, PortControlCreator *creator, PortControl::ControlType type,
414 AudioControl **audioControls, int offset, int len) {
415 void *jControl = NULL;
416 PortControl *control = (PortControl *)calloc(1, sizeof(PortControl));
417 float precision = 0.01;
418
419 control->type = type;
420 control->controlCount = len;
421 control->audioControls = (AudioControl **)malloc(len * sizeof(AudioControl *));
422 memcpy(control->audioControls, audioControls + offset, len * sizeof(AudioControl *));
423
424 switch (control->type) {
425 case PortControl::Volume:
426 jControl = creator->newFloatControl(creator, control, CONTROL_TYPE_VOLUME, 0, 1, precision, "");
427 break;
428 case PortControl::Mute:
429 jControl = creator->newBooleanControl(creator, control, CONTROL_TYPE_MUTE);
430 break;
431 case PortControl::Balance:
432 jControl = creator->newFloatControl(creator, control, CONTROL_TYPE_BALANCE, -1, 1, precision, "");
433 break;
434 };
435
436 if (jControl == NULL) {
437 ERROR0("CreatePortControl: javaControl was not created\n");
438 free(control->audioControls);
439 free(control);
440 return NULL;
441 }
465 // deviceControlCount is overestimated
466 // because we don't actually filter by if the owned objects are controls
467 err = GetAudioObjectPropertySize(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
468 kAudioObjectPropertyOwnedObjects, &size);
469
470 if (err) {
471 OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject size", portIndex);
472 } else {
473 mixer->deviceControlCount = size / sizeof(AudioObjectID);
474 TRACE1(" PORT_GetControls: detected %d owned objects\n", mixer->deviceControlCount);
475
476 AudioObjectID controlIDs[mixer->deviceControlCount];
477
478 err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
479 kAudioObjectPropertyOwnedObjects, sizeof(controlIDs), controlIDs, 1);
480
481 if (err) {
482 OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject values", portIndex);
483 } else {
484 mixer->deviceControls = (AudioControl *)calloc(mixer->deviceControlCount, sizeof(AudioControl));
485
486 for (int i = 0; i < mixer->deviceControlCount; i++) {
487 AudioControl *control = &mixer->deviceControls[i];
488
489 control->controlID = controlIDs[i];
490
491 OSStatus err1 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
492 kAudioObjectPropertyClass, sizeof(control->classID), &control->classID, 1);
493 OSStatus err2 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
494 kAudioControlPropertyScope, sizeof(control->scope), &control->scope, 1);
495 OSStatus err3 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
496 kAudioControlPropertyElement, sizeof(control->channel), &control->channel, 1);
497 if (err1 || err2 || err3) { // not a control or other error
498 control->classID = 0;
499 continue;
500 }
501
502 TRACE4("- control 0x%x, class='%s', scope='%s', channel=%d\n",
503 control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
504 }
598 if (masterMute != NULL) {
599 creator->addControl(creator, masterMute);
600 }
601
602 // don't add per-channel controls for mono & stereo - they are handled by "master" controls
603 // TODO: this should be reviewed to handle controls other than mute & volume
604 if (totalChannels > 2) {
605 // add separate compound control for each channel (containing volume and mute)
606 // (ensure that we have controls)
607 if (ValidControlCount(volumeControls, 1, totalChannels) > 0 || ValidControlCount(muteControls, 1, totalChannels) > 0) {
608 for (int ch=1; ch<=totalChannels; ch++) {
609 // get the channel name
610 char *channelName;
611 CFStringRef cfname = NULL;
612 const AudioObjectPropertyAddress address = {kAudioObjectPropertyElementName, port->scope, (unsigned)ch};
613 UInt32 size = sizeof(cfname);
614 OSStatus err = AudioObjectGetPropertyData(mixer->deviceID, &address, 0, NULL, &size, &cfname);
615 if (err == noErr) {
616 CFIndex length = CFStringGetLength(cfname) + 1;
617 channelName = (char *)malloc(length);
618 CFStringGetCString(cfname, channelName, length, kCFStringEncodingUTF8);
619 CFRelease(cfname);
620 } else {
621 channelName = (char *)malloc(16);
622 sprintf(channelName, "Ch %d", ch);
623 }
624
625 void* jControls[2];
626 int controlCount = 0;
627 if (volumeControls[ch] != NULL) {
628 jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, ch, 1);
629 }
630 if (muteControls[ch] != NULL) {
631 jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, ch, 1);
632 }
633 // TODO: add any extra controls for "other" controls for the channel
634
635 void *compoundControl = creator->newCompoundControl(creator, channelName, jControls, controlCount);
636 creator->addControl(creator, compoundControl);
637
638 free(channelName);
639 }
640 }
641 }
|
397 return TRUE;
398 }
399
400
401 // counts number of valid (non-NULL) elements in the array of AudioControls
402 static int ValidControlCount(AudioControl **arr, int offset, int len) {
403 int result = 0;
404 int end = offset + len;
405 for (int i=offset; i<end; i++) {
406 if (arr[i] != NULL)
407 result++;
408 }
409 return result;
410 }
411
412 // returns java control
413 static void* CreatePortControl(PortMixer *mixer, PortControlCreator *creator, PortControl::ControlType type,
414 AudioControl **audioControls, int offset, int len) {
415 void *jControl = NULL;
416 PortControl *control = (PortControl *)calloc(1, sizeof(PortControl));
417 if (control == NULL) {
418 return NULL;
419 }
420 float precision = 0.01;
421
422 control->type = type;
423 control->controlCount = len;
424 control->audioControls = (AudioControl **)malloc(len * sizeof(AudioControl *));
425 if (control->audioControls == NULL) {
426 free(control);
427 return NULL;
428 }
429 memcpy(control->audioControls, audioControls + offset, len * sizeof(AudioControl *));
430
431 switch (control->type) {
432 case PortControl::Volume:
433 jControl = creator->newFloatControl(creator, control, CONTROL_TYPE_VOLUME, 0, 1, precision, "");
434 break;
435 case PortControl::Mute:
436 jControl = creator->newBooleanControl(creator, control, CONTROL_TYPE_MUTE);
437 break;
438 case PortControl::Balance:
439 jControl = creator->newFloatControl(creator, control, CONTROL_TYPE_BALANCE, -1, 1, precision, "");
440 break;
441 };
442
443 if (jControl == NULL) {
444 ERROR0("CreatePortControl: javaControl was not created\n");
445 free(control->audioControls);
446 free(control);
447 return NULL;
448 }
472 // deviceControlCount is overestimated
473 // because we don't actually filter by if the owned objects are controls
474 err = GetAudioObjectPropertySize(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
475 kAudioObjectPropertyOwnedObjects, &size);
476
477 if (err) {
478 OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject size", portIndex);
479 } else {
480 mixer->deviceControlCount = size / sizeof(AudioObjectID);
481 TRACE1(" PORT_GetControls: detected %d owned objects\n", mixer->deviceControlCount);
482
483 AudioObjectID controlIDs[mixer->deviceControlCount];
484
485 err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal,
486 kAudioObjectPropertyOwnedObjects, sizeof(controlIDs), controlIDs, 1);
487
488 if (err) {
489 OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject values", portIndex);
490 } else {
491 mixer->deviceControls = (AudioControl *)calloc(mixer->deviceControlCount, sizeof(AudioControl));
492 if (mixer->deviceControls == NULL) {
493 return;
494 }
495
496 for (int i = 0; i < mixer->deviceControlCount; i++) {
497 AudioControl *control = &mixer->deviceControls[i];
498
499 control->controlID = controlIDs[i];
500
501 OSStatus err1 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
502 kAudioObjectPropertyClass, sizeof(control->classID), &control->classID, 1);
503 OSStatus err2 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
504 kAudioControlPropertyScope, sizeof(control->scope), &control->scope, 1);
505 OSStatus err3 = GetAudioObjectProperty(control->controlID, kAudioObjectPropertyScopeGlobal,
506 kAudioControlPropertyElement, sizeof(control->channel), &control->channel, 1);
507 if (err1 || err2 || err3) { // not a control or other error
508 control->classID = 0;
509 continue;
510 }
511
512 TRACE4("- control 0x%x, class='%s', scope='%s', channel=%d\n",
513 control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel);
514 }
608 if (masterMute != NULL) {
609 creator->addControl(creator, masterMute);
610 }
611
612 // don't add per-channel controls for mono & stereo - they are handled by "master" controls
613 // TODO: this should be reviewed to handle controls other than mute & volume
614 if (totalChannels > 2) {
615 // add separate compound control for each channel (containing volume and mute)
616 // (ensure that we have controls)
617 if (ValidControlCount(volumeControls, 1, totalChannels) > 0 || ValidControlCount(muteControls, 1, totalChannels) > 0) {
618 for (int ch=1; ch<=totalChannels; ch++) {
619 // get the channel name
620 char *channelName;
621 CFStringRef cfname = NULL;
622 const AudioObjectPropertyAddress address = {kAudioObjectPropertyElementName, port->scope, (unsigned)ch};
623 UInt32 size = sizeof(cfname);
624 OSStatus err = AudioObjectGetPropertyData(mixer->deviceID, &address, 0, NULL, &size, &cfname);
625 if (err == noErr) {
626 CFIndex length = CFStringGetLength(cfname) + 1;
627 channelName = (char *)malloc(length);
628 if (channelName == NULL) {
629 return;
630 }
631 CFStringGetCString(cfname, channelName, length, kCFStringEncodingUTF8);
632 CFRelease(cfname);
633 } else {
634 channelName = (char *)malloc(16);
635 if (channelName == NULL) {
636 return;
637 }
638 sprintf(channelName, "Ch %d", ch);
639 }
640
641 void* jControls[2];
642 int controlCount = 0;
643 if (volumeControls[ch] != NULL) {
644 jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Volume, volumeControls, ch, 1);
645 }
646 if (muteControls[ch] != NULL) {
647 jControls[controlCount++] = CreatePortControl(mixer, creator, PortControl::Mute, muteControls, ch, 1);
648 }
649 // TODO: add any extra controls for "other" controls for the channel
650
651 void *compoundControl = creator->newCompoundControl(creator, channelName, jControls, controlCount);
652 creator->addControl(creator, compoundControl);
653
654 free(channelName);
655 }
656 }
657 }
|