2 * Copyright 2007-2010, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Ithamar Adema, ithamar AT unet DOT nl
7 * Axel Dörfler, axeld@pinc-software.de
11 #include "hmulti_audio.h"
19 //#define TRACE_MULTI_AUDIO
20 #ifdef TRACE_MULTI_AUDIO
21 # define TRACE(a...) dprintf("hda: " a)
23 # define TRACE(a...) ;
25 #define ERROR(a...) dprintf("hda: " a)
30 B_MIX_MUX_MIXER
= 1 << 2,
31 B_MIX_MUX_SELECTOR
= 1 << 3
35 static multi_channel_info sChannels
[] = {
36 { 0, B_MULTI_OUTPUT_CHANNEL
, B_CHANNEL_LEFT
| B_CHANNEL_STEREO_BUS
, 0 },
37 { 1, B_MULTI_OUTPUT_CHANNEL
, B_CHANNEL_RIGHT
| B_CHANNEL_STEREO_BUS
, 0 },
38 { 2, B_MULTI_INPUT_CHANNEL
, B_CHANNEL_LEFT
| B_CHANNEL_STEREO_BUS
, 0 },
39 { 3, B_MULTI_INPUT_CHANNEL
, B_CHANNEL_RIGHT
| B_CHANNEL_STEREO_BUS
, 0 },
40 { 4, B_MULTI_OUTPUT_BUS
, B_CHANNEL_LEFT
| B_CHANNEL_STEREO_BUS
,
41 B_CHANNEL_MINI_JACK_STEREO
},
42 { 5, B_MULTI_OUTPUT_BUS
, B_CHANNEL_RIGHT
| B_CHANNEL_STEREO_BUS
,
43 B_CHANNEL_MINI_JACK_STEREO
},
44 { 6, B_MULTI_INPUT_BUS
, B_CHANNEL_LEFT
| B_CHANNEL_STEREO_BUS
,
45 B_CHANNEL_MINI_JACK_STEREO
},
46 { 7, B_MULTI_INPUT_BUS
, B_CHANNEL_RIGHT
| B_CHANNEL_STEREO_BUS
,
47 B_CHANNEL_MINI_JACK_STEREO
},
52 format2size(uint32 format
)
73 get_description(hda_audio_group
* audioGroup
, multi_description
* data
)
75 data
->interface_version
= B_CURRENT_INTERFACE_VERSION
;
76 data
->interface_minimum
= B_CURRENT_INTERFACE_VERSION
;
78 strcpy(data
->friendly_name
, "HD Audio");
79 strcpy(data
->vendor_info
, "Haiku");
82 if (audioGroup
->record_stream
!= NULL
)
85 int32 outChannels
= 0;
86 if (audioGroup
->playback_stream
!= NULL
)
89 data
->output_channel_count
= outChannels
;
90 data
->output_bus_channel_count
= outChannels
;
91 data
->input_channel_count
= inChannels
;
92 data
->input_bus_channel_count
= inChannels
;
93 data
->aux_bus_channel_count
= 0;
95 TRACE("%s: request_channel_count: %ld\n", __func__
,
96 data
->request_channel_count
);
98 if (data
->request_channel_count
>= (int)(sizeof(sChannels
)
99 / sizeof(sChannels
[0]))) {
100 memcpy(data
->channels
, &sChannels
, sizeof(sChannels
));
103 if (audioGroup
->playback_stream
!= NULL
) {
104 data
->output_rates
= audioGroup
->playback_stream
->sample_rate
;
105 data
->output_formats
= audioGroup
->playback_stream
->sample_format
;
107 data
->output_rates
= 0;
108 data
->output_formats
= 0;
111 if (audioGroup
->record_stream
!= NULL
) {
112 data
->input_rates
= audioGroup
->record_stream
->sample_rate
;
113 data
->input_formats
= audioGroup
->record_stream
->sample_format
;
115 data
->input_rates
= 0;
116 data
->input_formats
= 0;
119 // force existance of 48kHz if variable rates are not supported
120 if (data
->output_rates
== 0)
121 data
->output_rates
= B_SR_48000
;
122 if (data
->input_rates
== 0)
123 data
->input_rates
= B_SR_48000
;
125 data
->max_cvsr_rate
= 0;
126 data
->min_cvsr_rate
= 0;
128 data
->lock_sources
= B_MULTI_LOCK_INTERNAL
;
129 data
->timecode_sources
= 0;
130 data
->interface_flags
131 = B_MULTI_INTERFACE_PLAYBACK
| B_MULTI_INTERFACE_RECORD
;
132 data
->start_latency
= 30000;
134 strcpy(data
->control_panel
, "");
141 get_enabled_channels(hda_audio_group
* audioGroup
, multi_channel_enable
* data
)
143 B_SET_CHANNEL(data
->enable_bits
, 0, true);
144 B_SET_CHANNEL(data
->enable_bits
, 1, true);
145 B_SET_CHANNEL(data
->enable_bits
, 2, true);
146 B_SET_CHANNEL(data
->enable_bits
, 3, true);
147 data
->lock_source
= B_MULTI_LOCK_INTERNAL
;
154 get_global_format(hda_audio_group
* audioGroup
, multi_format_info
* data
)
156 data
->output_latency
= 0;
157 data
->input_latency
= 0;
158 data
->timecode_kind
= 0;
160 if (audioGroup
->playback_stream
!= NULL
) {
161 data
->output
.format
= audioGroup
->playback_stream
->sample_format
;
162 data
->output
.rate
= audioGroup
->playback_stream
->sample_rate
;
164 data
->output
.format
= 0;
165 data
->output
.rate
= 0;
168 if (audioGroup
->record_stream
!= NULL
) {
169 data
->input
.format
= audioGroup
->record_stream
->sample_format
;
170 data
->input
.rate
= audioGroup
->record_stream
->sample_rate
;
172 data
->input
.format
= 0;
173 data
->input
.rate
= 0;
181 set_global_format(hda_audio_group
* audioGroup
, multi_format_info
* data
)
183 // TODO: it looks like we're not supposed to fail; fix this!
185 if ((data
->output
.format
& audioGroup
->supported_formats
) == 0)
186 || (data
->output
.rate
& audioGroup
->supported_rates
) == 0)
190 if (audioGroup
->playback_stream
!= NULL
) {
191 audioGroup
->playback_stream
->sample_format
= data
->output
.format
;
192 audioGroup
->playback_stream
->sample_rate
= data
->output
.rate
;
193 audioGroup
->playback_stream
->sample_size
= format2size(
194 audioGroup
->playback_stream
->sample_format
);
197 if (audioGroup
->record_stream
!= NULL
) {
198 audioGroup
->record_stream
->sample_rate
= data
->input
.rate
;
199 audioGroup
->record_stream
->sample_format
= data
->input
.format
;
200 audioGroup
->record_stream
->sample_size
= format2size(
201 audioGroup
->record_stream
->sample_format
);
208 static enum strind_id
209 hda_find_multi_string(hda_widget
& widget
)
211 switch (CONF_DEFAULT_DEVICE(widget
.d
.pin
.config
)) {
214 case PIN_DEV_LINE_IN
:
215 case PIN_DEV_LINE_OUT
:
221 case PIN_DEV_SPDIF_IN
:
222 case PIN_DEV_SPDIF_OUT
:
224 case PIN_DEV_HEAD_PHONE_OUT
:
227 ERROR("couln't find a string for widget %ld in hda_find_multi_string()\n",
234 hda_find_multi_custom_string(hda_widget
& widget
, char* custom
, uint32 size
)
236 const char* device
= NULL
;
237 switch (CONF_DEFAULT_DEVICE(widget
.d
.pin
.config
)) {
238 case PIN_DEV_LINE_IN
:
240 case PIN_DEV_LINE_OUT
:
246 switch (CONF_DEFAULT_COLOR(widget
.d
.pin
.config
)) {
260 device
= "Center/Sub";
267 case PIN_DEV_SPDIF_IN
:
270 case PIN_DEV_SPDIF_OUT
:
271 device
= "SPDIF out";
276 case PIN_DEV_HEAD_PHONE_OUT
:
277 device
= "Headphones";
279 case PIN_DEV_SPEAKER
:
283 if (device
== NULL
) {
284 ERROR("couldn't find a string for widget %ld in "
285 "hda_find_multi_custom_string()\n", widget
.node_id
);
289 = get_widget_location(CONF_DEFAULT_LOCATION(widget
.d
.pin
.config
));
290 snprintf(custom
, size
, "%s%s%s", location
? location
: "",
291 location
? " " : "", device
);
296 hda_create_group_control(hda_multi
*multi
, uint32
*index
, int32 parent
,
297 enum strind_id string
, const char* name
)
301 multi
->controls
[i
].mix_control
.id
= MULTI_CONTROL_FIRSTID
+ i
;
302 multi
->controls
[i
].mix_control
.parent
= parent
;
303 multi
->controls
[i
].mix_control
.flags
= B_MULTI_MIX_GROUP
;
304 multi
->controls
[i
].mix_control
.master
= MULTI_CONTROL_MASTERID
;
305 multi
->controls
[i
].mix_control
.string
= string
;
307 strcpy(multi
->controls
[i
].mix_control
.name
, name
);
309 return multi
->controls
[i
].mix_control
.id
;
314 hda_create_channel_control(hda_multi
* multi
, uint32
* index
, int32 parent
,
315 int32 string
, hda_widget
& widget
, bool input
, uint32 capabilities
,
316 int32 inputIndex
, bool& gain
, bool& mute
)
318 uint32 i
= *index
, id
;
319 hda_multi_mixer_control control
;
321 control
.nid
= widget
.node_id
;
322 control
.input
= input
;
325 control
.capabilities
= capabilities
;
326 control
.index
= inputIndex
;
327 control
.mix_control
.master
= MULTI_CONTROL_MASTERID
;
328 control
.mix_control
.parent
= parent
;
330 if (mute
&& (capabilities
& AMP_CAP_MUTE
) != 0) {
331 control
.mix_control
.id
= MULTI_CONTROL_FIRSTID
+ i
;
332 control
.mix_control
.flags
= B_MULTI_MIX_ENABLE
;
333 control
.mix_control
.string
= S_MUTE
;
334 control
.type
= B_MIX_MUTE
;
335 multi
->controls
[i
++] = control
;
336 TRACE("control nid %ld mute\n", control
.nid
);
340 if (gain
&& AMP_CAP_NUM_STEPS(capabilities
) >= 1) {
341 control
.mix_control
.gain
.granularity
= AMP_CAP_STEP_SIZE(capabilities
);
342 control
.mix_control
.gain
.min_gain
= (0.0 - AMP_CAP_OFFSET(capabilities
))
343 * control
.mix_control
.gain
.granularity
;
344 control
.mix_control
.gain
.max_gain
= (AMP_CAP_NUM_STEPS(capabilities
)
345 - AMP_CAP_OFFSET(capabilities
))
346 * control
.mix_control
.gain
.granularity
;
348 control
.mix_control
.id
= MULTI_CONTROL_FIRSTID
+ i
;
349 control
.mix_control
.flags
= B_MULTI_MIX_GAIN
;
350 control
.mix_control
.string
= S_null
;
351 control
.type
= B_MIX_GAIN
;
352 strcpy(control
.mix_control
.name
, "Gain");
353 multi
->controls
[i
++] = control
;
354 id
= control
.mix_control
.id
;
357 control
.mix_control
.id
= MULTI_CONTROL_FIRSTID
+ i
;
358 control
.mix_control
.master
= id
;
359 multi
->controls
[i
++] = control
;
360 TRACE("control nid %ld %f min %f max %f\n", control
.nid
,
361 control
.mix_control
.gain
.granularity
,
362 control
.mix_control
.gain
.min_gain
,
363 control
.mix_control
.gain
.max_gain
);
372 hda_create_mux_control(hda_multi
*multi
, uint32
*index
, int32 parent
,
375 uint32 i
= *index
, parent2
;
376 hda_multi_mixer_control control
;
377 hda_audio_group
*audioGroup
= multi
->group
;
379 control
.nid
= widget
.node_id
;
380 control
.input
= true;
383 control
.mix_control
.master
= MULTI_CONTROL_MASTERID
;
384 control
.mix_control
.parent
= parent
;
385 control
.mix_control
.id
= MULTI_CONTROL_FIRSTID
+ i
;
386 control
.mix_control
.flags
= B_MULTI_MIX_MUX
;
387 control
.mix_control
.string
= S_null
;
388 control
.type
= widget
.type
== WT_AUDIO_MIXER
389 ? B_MIX_MUX_MIXER
: B_MIX_MUX_SELECTOR
;
390 multi
->controls
[i
] = control
;
391 strcpy(multi
->controls
[i
].mix_control
.name
, "");
393 parent2
= control
.mix_control
.id
;
395 for (uint32 j
= 0; j
< widget
.num_inputs
; j
++) {
397 hda_audio_group_get_widget(audioGroup
, widget
.inputs
[j
]);
398 if (input
->type
!= WT_PIN_COMPLEX
)
400 control
.nid
= widget
.node_id
;
401 control
.input
= true;
402 control
.mix_control
.id
= MULTI_CONTROL_FIRSTID
+ i
;
403 control
.mix_control
.flags
= B_MULTI_MIX_MUX_VALUE
;
404 control
.mix_control
.parent
= parent2
;
405 control
.mix_control
.string
= S_null
;
406 multi
->controls
[i
] = control
;
407 hda_find_multi_custom_string(*input
,
408 multi
->controls
[i
].mix_control
.name
,
409 sizeof(multi
->controls
[i
].mix_control
.name
));
418 hda_create_control_for_complex(hda_multi
* multi
, uint32
* index
, uint32 parent
,
419 hda_widget
& widget
, bool& gain
, bool& mute
)
421 hda_audio_group
* audioGroup
= multi
->group
;
423 switch (widget
.type
) {
424 case WT_AUDIO_OUTPUT
:
426 case WT_AUDIO_SELECTOR
:
433 if ((widget
.flags
& WIDGET_FLAG_WIDGET_PATH
) != 0)
436 TRACE(" create widget nid %lu\n", widget
.node_id
);
437 hda_create_channel_control(multi
, index
, parent
, 0,
438 widget
, false, widget
.capabilities
.output_amplifier
, 0, gain
, mute
);
440 if (!gain
&& !mute
) {
441 widget
.flags
|= WIDGET_FLAG_WIDGET_PATH
;
445 if (widget
.type
== WT_AUDIO_MIXER
) {
446 hda_create_channel_control(multi
, index
, parent
, 0,
447 widget
, true, widget
.capabilities
.input_amplifier
, 0, gain
, mute
);
448 if (!gain
&& !mute
) {
449 widget
.flags
|= WIDGET_FLAG_WIDGET_PATH
;
454 if (widget
.type
!= WT_AUDIO_OUTPUT
&& widget
.num_inputs
> 0) {
455 hda_widget
& child
= *hda_audio_group_get_widget(audioGroup
,
456 widget
.inputs
[widget
.active_input
]);
457 hda_create_control_for_complex(multi
, index
, parent
, child
, gain
, mute
);
460 widget
.flags
|= WIDGET_FLAG_WIDGET_PATH
;
465 hda_create_controls_list(hda_multi
* multi
)
468 hda_audio_group
* audioGroup
= multi
->group
;
470 uint32 parent
= hda_create_group_control(multi
, &index
, 0, S_OUTPUT
, NULL
);
473 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
474 hda_widget
& complex = audioGroup
->widgets
[i
];
477 if (complex.type
!= WT_PIN_COMPLEX
)
479 if (!PIN_CAP_IS_OUTPUT(complex.d
.pin
.capabilities
))
481 if ((complex.flags
& WIDGET_FLAG_OUTPUT_PATH
) == 0)
484 TRACE("create complex nid %lu\n", complex.node_id
);
485 hda_find_multi_custom_string(complex, name
, sizeof(name
));
486 parent2
= hda_create_group_control(multi
, &index
, parent
, S_null
, name
);
487 bool gain
= true, mute
= true;
489 hda_create_control_for_complex(multi
, &index
, parent2
, complex, gain
,
493 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
494 hda_widget
& widget
= audioGroup
->widgets
[i
];
496 if (widget
.type
!= WT_AUDIO_MIXER
)
498 if ((widget
.flags
& WIDGET_FLAG_WIDGET_PATH
) != 0)
501 TRACE("create widget nid %lu\n", widget
.node_id
);
503 if (AMP_CAP_NUM_STEPS(widget
.capabilities
.input_amplifier
) >= 1) {
504 for (uint32 j
= 0; j
< widget
.num_inputs
; j
++) {
505 hda_widget
* complex = hda_audio_group_get_widget(audioGroup
,
508 if (complex->type
!= WT_PIN_COMPLEX
)
510 if (!PIN_CAP_IS_INPUT(complex->d
.pin
.capabilities
))
512 if ((complex->flags
& WIDGET_FLAG_OUTPUT_PATH
) != 0)
514 TRACE(" create widget input nid %lu\n", widget
.inputs
[j
]);
515 hda_find_multi_custom_string(*complex, name
, sizeof(name
));
516 parent2
= hda_create_group_control(multi
, &index
,
517 parent
, S_null
, name
);
518 bool gain
= true, mute
= true;
519 hda_create_channel_control(multi
, &index
, parent2
, 0, widget
,
520 true, widget
.capabilities
.input_amplifier
, j
, gain
, mute
);
524 widget
.flags
|= WIDGET_FLAG_WIDGET_PATH
;
527 parent
= hda_create_group_control(multi
, &index
, 0, S_INPUT
, NULL
);
529 for (uint32 i
= 0; i
< audioGroup
->widget_count
; i
++) {
530 hda_widget
& widget
= audioGroup
->widgets
[i
];
532 if (widget
.type
!= WT_AUDIO_INPUT
)
535 uint32 capabilities
= widget
.capabilities
.input_amplifier
;
536 if (AMP_CAP_NUM_STEPS(capabilities
) < 1)
539 parent2
= hda_create_group_control(multi
, &index
,
540 parent
, hda_find_multi_string(widget
), "Input");
541 bool gain
= true, mute
= true;
542 hda_create_channel_control(multi
, &index
, parent2
, 0,
543 widget
, true, capabilities
, 0, gain
, mute
);
545 if (widget
.num_inputs
> 1) {
546 TRACE(" create mux for nid %lu\n", widget
.node_id
);
547 hda_create_mux_control(multi
, &index
, parent2
, widget
);
551 hda_widget
*mixer
= hda_audio_group_get_widget(audioGroup
,
553 if (mixer
->type
!= WT_AUDIO_MIXER
&& mixer
->type
!= WT_AUDIO_SELECTOR
)
555 TRACE(" create mixer nid %lu\n", mixer
->node_id
);
556 hda_create_mux_control(multi
, &index
, parent2
, *mixer
);
559 multi
->control_count
= index
;
560 TRACE("multi->control_count %lu\n", multi
->control_count
);
566 list_mix_controls(hda_audio_group
* audioGroup
, multi_mix_control_info
* mmci
)
568 multi_mix_control
*mmc
= mmci
->controls
;
569 if (mmci
->control_count
< 24)
572 if (hda_create_controls_list(audioGroup
->multi
) < B_OK
)
574 for (uint32 i
= 0; i
< audioGroup
->multi
->control_count
; i
++) {
575 mmc
[i
] = audioGroup
->multi
->controls
[i
].mix_control
;
578 mmci
->control_count
= audioGroup
->multi
->control_count
;
584 list_mix_connections(hda_audio_group
* audioGroup
,
585 multi_mix_connection_info
* data
)
587 data
->actual_count
= 0;
593 list_mix_channels(hda_audio_group
* audioGroup
, multi_mix_channel_info
*data
)
600 get_control_gain_mute(hda_audio_group
* audioGroup
,
601 hda_multi_mixer_control
*control
, uint32
*resp
)
604 verb
[0] = MAKE_VERB(audioGroup
->codec
->addr
,
606 VID_GET_AMPLIFIER_GAIN_MUTE
,
607 (control
->input
? AMP_GET_INPUT
: AMP_GET_OUTPUT
)
608 | AMP_GET_LEFT_CHANNEL
| AMP_GET_INPUT_INDEX(control
->index
));
609 verb
[1] = MAKE_VERB(audioGroup
->codec
->addr
,
611 VID_GET_AMPLIFIER_GAIN_MUTE
,
612 (control
->input
? AMP_GET_INPUT
: AMP_GET_OUTPUT
)
613 | AMP_GET_RIGHT_CHANNEL
| AMP_GET_INPUT_INDEX(control
->index
));
614 hda_send_verbs(audioGroup
->codec
, verb
, resp
, 2);
619 get_mix(hda_audio_group
* audioGroup
, multi_mix_value_info
* mmvi
)
622 hda_multi_mixer_control
*control
= NULL
;
623 for (int32 i
= 0; i
< mmvi
->item_count
; i
++) {
624 id
= mmvi
->values
[i
].id
- MULTI_CONTROL_FIRSTID
;
625 if (id
< 0 || id
>= audioGroup
->multi
->control_count
) {
626 dprintf("hda: get_mix : invalid control id requested : %li\n", id
);
629 control
= &audioGroup
->multi
->controls
[id
];
631 if ((control
->mix_control
.flags
632 & (B_MULTI_MIX_GAIN
| B_MULTI_MIX_ENABLE
)) != 0) {
634 get_control_gain_mute(audioGroup
, control
, resp
);
635 if ((control
->mix_control
.flags
& B_MULTI_MIX_ENABLE
) != 0) {
636 mmvi
->values
[i
].enable
= (resp
[0] & AMP_MUTE
) != 0;
637 TRACE("get_mix: %ld mute: %d\n", control
->nid
,
638 mmvi
->values
[i
].enable
);
639 } else if ((control
->mix_control
.flags
& B_MULTI_MIX_GAIN
) != 0) {
641 if (control
->mix_control
.master
== MULTI_CONTROL_MASTERID
)
642 value
= resp
[0] & AMP_GAIN_MASK
;
644 value
= resp
[1] & AMP_GAIN_MASK
;
645 mmvi
->values
[i
].gain
= (0.0 + value
- AMP_CAP_OFFSET(control
->capabilities
))
646 * AMP_CAP_STEP_SIZE(control
->capabilities
);
647 TRACE("get_mix: %ld gain: %f (%ld)\n", control
->nid
, mmvi
->values
[i
].gain
, value
);
650 } else if ((control
->mix_control
.flags
& B_MIX_MUX_MIXER
) != 0) {
651 hda_widget
* mixer
= hda_audio_group_get_widget(audioGroup
,
653 mmvi
->values
[i
].mux
= 0;
654 for (uint32 j
= 0; j
< mixer
->num_inputs
; j
++) {
655 uint32 verb
= MAKE_VERB(audioGroup
->codec
->addr
,
656 control
->nid
, VID_GET_AMPLIFIER_GAIN_MUTE
, AMP_GET_INPUT
657 | AMP_GET_LEFT_CHANNEL
| AMP_GET_INPUT_INDEX(j
));
659 if (hda_send_verbs(audioGroup
->codec
, &verb
, &resp
, 1) == B_OK
) {
660 TRACE("get_mix: %ld mixer %ld is %smute\n", control
->nid
,
661 j
, (resp
& AMP_MUTE
) != 0 ? "" : "un");
662 if ((resp
& AMP_MUTE
) == 0) {
663 mmvi
->values
[i
].mux
= j
;
664 #ifndef TRACE_MULTI_AUDIO
670 TRACE("get_mix: %ld mixer: %ld\n", control
->nid
,
671 mmvi
->values
[i
].mux
);
672 } else if ((control
->mix_control
.flags
& B_MIX_MUX_SELECTOR
) != 0) {
673 uint32 verb
= MAKE_VERB(audioGroup
->codec
->addr
, control
->nid
,
674 VID_GET_CONNECTION_SELECT
, 0);
676 if (hda_send_verbs(audioGroup
->codec
, &verb
, &resp
, 1) == B_OK
)
677 mmvi
->values
[i
].mux
= resp
& 0xff;
678 TRACE("get_mix: %ld selector: %ld\n", control
->nid
,
679 mmvi
->values
[i
].mux
);
687 set_mix(hda_audio_group
* audioGroup
, multi_mix_value_info
* mmvi
)
690 hda_multi_mixer_control
*control
= NULL
;
691 for (int32 i
= 0; i
< mmvi
->item_count
; i
++) {
692 id
= mmvi
->values
[i
].id
- MULTI_CONTROL_FIRSTID
;
693 if (id
< 0 || id
>= audioGroup
->multi
->control_count
) {
694 dprintf("set_mix : invalid control id requested : %li\n", id
);
697 control
= &audioGroup
->multi
->controls
[id
];
699 if ((control
->mix_control
.flags
& B_MULTI_MIX_ENABLE
) != 0) {
700 control
->mute
= (mmvi
->values
[i
].enable
? AMP_MUTE
: 0);
701 TRACE("set_mix: %ld mute: %lx\n", control
->nid
, control
->mute
);
703 get_control_gain_mute(audioGroup
, control
, resp
);
706 verb
[0] = MAKE_VERB(audioGroup
->codec
->addr
,
708 VID_SET_AMPLIFIER_GAIN_MUTE
,
709 (control
->input
? AMP_SET_INPUT
: AMP_SET_OUTPUT
)
710 | AMP_SET_LEFT_CHANNEL
711 | AMP_SET_INPUT_INDEX(control
->index
)
713 | (resp
[0] & AMP_GAIN_MASK
));
714 TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control
->nid
,
715 control
->mute
, resp
[0] & AMP_GAIN_MASK
, control
->input
,
716 (control
->input
? AMP_SET_INPUT
: AMP_SET_OUTPUT
)
717 | AMP_SET_LEFT_CHANNEL
718 | AMP_SET_INPUT_INDEX(control
->index
)
720 | (resp
[0] & AMP_GAIN_MASK
));
721 verb
[1] = MAKE_VERB(audioGroup
->codec
->addr
,
723 VID_SET_AMPLIFIER_GAIN_MUTE
,
724 (control
->input
? AMP_SET_INPUT
: AMP_SET_OUTPUT
)
725 | AMP_SET_RIGHT_CHANNEL
726 | AMP_SET_INPUT_INDEX(control
->index
)
728 | (resp
[1] & AMP_GAIN_MASK
));
729 TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n", control
->nid
,
730 control
->mute
, resp
[1] & AMP_GAIN_MASK
, control
->input
);
731 hda_send_verbs(audioGroup
->codec
, verb
, NULL
, 2);
732 } else if ((control
->mix_control
.flags
& B_MULTI_MIX_GAIN
) != 0) {
733 hda_multi_mixer_control
*control2
= NULL
;
734 if (i
+1<mmvi
->item_count
) {
735 id
= mmvi
->values
[i
+ 1].id
- MULTI_CONTROL_FIRSTID
;
736 if (id
< 0 || id
>= audioGroup
->multi
->control_count
) {
737 dprintf("set_mix : invalid control id requested : %li\n", id
);
739 control2
= &audioGroup
->multi
->controls
[id
];
740 if (control2
->mix_control
.master
!= control
->mix_control
.id
)
745 if (control
->mix_control
.master
== MULTI_CONTROL_MASTERID
) {
746 control
->gain
= (uint32
)(mmvi
->values
[i
].gain
747 / AMP_CAP_STEP_SIZE(control
->capabilities
)
748 + AMP_CAP_OFFSET(control
->capabilities
));
752 && control2
->mix_control
.master
!= MULTI_CONTROL_MASTERID
) {
753 control2
->gain
= (uint32
)(mmvi
->values
[i
+1].gain
754 / AMP_CAP_STEP_SIZE(control2
->capabilities
)
755 + AMP_CAP_OFFSET(control2
->capabilities
));
757 TRACE("set_mix: %ld gain: %lx and %ld gain: %lx\n",
758 control
->nid
, control
->gain
, control2
->nid
, control2
->gain
);
760 get_control_gain_mute(audioGroup
, control
, resp
);
761 control
->mute
= resp
[0] & AMP_MUTE
;
763 control2
->mute
= resp
[1] & AMP_MUTE
;
766 verb
[0] = MAKE_VERB(audioGroup
->codec
->addr
,
768 VID_SET_AMPLIFIER_GAIN_MUTE
,
769 (control
->input
? AMP_SET_INPUT
: AMP_SET_OUTPUT
)
770 | AMP_SET_LEFT_CHANNEL
771 | AMP_SET_INPUT_INDEX(control
->index
)
772 | (control
->mute
& AMP_MUTE
)
773 | (control
->gain
& AMP_GAIN_MASK
));
774 TRACE("set_mix: sending verb to %ld: %lx %lx %x %lx\n", control
->nid
,
775 control
->mute
, control
->gain
, control
->input
,
776 (control
->input
? AMP_SET_INPUT
: AMP_SET_OUTPUT
)
777 | AMP_SET_LEFT_CHANNEL
778 | AMP_SET_INPUT_INDEX(control
->index
)
779 | (control
->mute
& AMP_MUTE
)
780 | (control
->gain
& AMP_GAIN_MASK
));
782 verb
[1] = MAKE_VERB(audioGroup
->codec
->addr
,
784 VID_SET_AMPLIFIER_GAIN_MUTE
,
785 (control
->input
? AMP_SET_INPUT
: AMP_SET_OUTPUT
)
786 | AMP_SET_RIGHT_CHANNEL
787 | AMP_SET_INPUT_INDEX(control
->index
)
788 | (control2
->mute
& AMP_MUTE
)
789 | (control2
->gain
& AMP_GAIN_MASK
));
790 TRACE("set_mix: ctrl2 sending verb to %ld: %lx %lx %x\n",
791 control2
->nid
, control2
->mute
, control2
->gain
,
794 hda_send_verbs(audioGroup
->codec
, verb
, NULL
, control2
? 2 : 1);
798 } else if ((control
->mix_control
.flags
& B_MIX_MUX_MIXER
) != 0) {
799 TRACE("set_mix: %ld mixer: %ld\n", control
->nid
, mmvi
->values
[i
].mux
);
800 hda_widget
*mixer
= hda_audio_group_get_widget(audioGroup
,
802 uint32 verb
[mixer
->num_inputs
];
803 for (uint32 j
= 0; j
< mixer
->num_inputs
; j
++) {
804 verb
[j
] = MAKE_VERB(audioGroup
->codec
->addr
,
805 control
->nid
, VID_SET_AMPLIFIER_GAIN_MUTE
, AMP_SET_INPUT
806 | AMP_SET_LEFT_CHANNEL
| AMP_SET_RIGHT_CHANNEL
807 | AMP_SET_INPUT_INDEX(j
)
808 | ((mmvi
->values
[i
].mux
== j
) ? 0 : AMP_MUTE
));
809 TRACE("set_mix: %ld mixer %smuting %ld (%lx)\n", control
->nid
,
810 (mmvi
->values
[i
].mux
== j
) ? "un" : "", j
, verb
[j
]);
812 if (hda_send_verbs(audioGroup
->codec
, verb
, NULL
, mixer
->num_inputs
)
814 dprintf("hda: Setting mixer %ld failed on widget %ld!\n",
815 mmvi
->values
[i
].mux
, control
->nid
);
816 } else if ((control
->mix_control
.flags
& B_MIX_MUX_SELECTOR
) != 0) {
817 uint32 verb
= MAKE_VERB(audioGroup
->codec
->addr
, control
->nid
,
818 VID_SET_CONNECTION_SELECT
, mmvi
->values
[i
].mux
);
819 if (hda_send_verbs(audioGroup
->codec
, &verb
, NULL
, 1) != B_OK
) {
820 dprintf("hda: Setting output selector %ld failed on widget "
821 "%ld!\n", mmvi
->values
[i
].mux
, control
->nid
);
823 TRACE("set_mix: %ld selector: %ld\n", control
->nid
,
824 mmvi
->values
[i
].mux
);
832 default_buffer_length_for_rate(uint32 rate
)
834 // keep the latency about the same as 2048 frames per buffer at 44100 Hz
866 get_buffers(hda_audio_group
* audioGroup
, multi_buffer_list
* data
)
868 TRACE("playback: %ld buffers, %ld channels, %ld samples\n",
869 data
->request_playback_buffers
, data
->request_playback_channels
,
870 data
->request_playback_buffer_size
);
871 TRACE("record: %ld buffers, %ld channels, %ld samples\n",
872 data
->request_record_buffers
, data
->request_record_channels
,
873 data
->request_record_buffer_size
);
875 /* Determine what buffers we return given the request */
877 data
->return_playback_buffers
= data
->request_playback_buffers
;
878 data
->return_playback_channels
= data
->request_playback_channels
;
879 data
->return_playback_buffer_size
= data
->request_playback_buffer_size
;
880 data
->return_record_buffers
= data
->request_record_buffers
;
881 data
->return_record_channels
= data
->request_record_channels
;
882 data
->return_record_buffer_size
= data
->request_record_buffer_size
;
884 /* Workaround for Haiku multi_audio API, since it prefers to let the
885 driver pick values, while the BeOS multi_audio actually gives the
887 if (data
->return_playback_buffers
> STREAM_MAX_BUFFERS
888 || data
->return_playback_buffers
< STREAM_MIN_BUFFERS
)
889 data
->return_playback_buffers
= STREAM_MIN_BUFFERS
;
891 if (data
->return_record_buffers
> STREAM_MAX_BUFFERS
892 || data
->return_record_buffers
< STREAM_MIN_BUFFERS
)
893 data
->return_record_buffers
= STREAM_MIN_BUFFERS
;
895 if (data
->return_playback_buffer_size
== 0
896 && audioGroup
->playback_stream
!= NULL
) {
897 data
->return_playback_buffer_size
= default_buffer_length_for_rate(
898 audioGroup
->playback_stream
->sample_rate
);
901 if (data
->return_record_buffer_size
== 0
902 && audioGroup
->record_stream
!= NULL
) {
903 data
->return_record_buffer_size
= default_buffer_length_for_rate(
904 audioGroup
->record_stream
->sample_rate
);
907 /* ... from here on, we can assume again that a reasonable request is
910 data
->flags
= B_MULTI_BUFFER_PLAYBACK
| B_MULTI_BUFFER_RECORD
;
912 /* Copy the settings into the streams */
914 if (audioGroup
->playback_stream
!= NULL
) {
915 audioGroup
->playback_stream
->num_buffers
= data
->return_playback_buffers
;
916 audioGroup
->playback_stream
->num_channels
= data
->return_playback_channels
;
917 audioGroup
->playback_stream
->buffer_length
918 = data
->return_playback_buffer_size
;
920 status_t status
= hda_stream_setup_buffers(audioGroup
,
921 audioGroup
->playback_stream
, "Playback");
922 if (status
!= B_OK
) {
923 dprintf("hda: Error setting up playback buffers: %s\n",
929 if (audioGroup
->record_stream
!= NULL
) {
930 audioGroup
->record_stream
->num_buffers
= data
->return_record_buffers
;
931 audioGroup
->record_stream
->num_channels
= data
->return_record_channels
;
932 audioGroup
->record_stream
->buffer_length
933 = data
->return_record_buffer_size
;
935 status_t status
= hda_stream_setup_buffers(audioGroup
,
936 audioGroup
->record_stream
, "Recording");
937 if (status
!= B_OK
) {
938 dprintf("hda: Error setting up recording buffers: %s\n",
944 /* Setup data structure for multi_audio API... */
946 if (audioGroup
->playback_stream
!= NULL
) {
947 uint32 playbackSampleSize
= audioGroup
->playback_stream
->sample_size
;
949 for (int32 i
= 0; i
< data
->return_playback_buffers
; i
++) {
950 for (int32 channelIndex
= 0;
951 channelIndex
< data
->return_playback_channels
; channelIndex
++) {
952 data
->playback_buffers
[i
][channelIndex
].base
953 = (char*)audioGroup
->playback_stream
->buffers
[i
]
954 + playbackSampleSize
* channelIndex
;
955 data
->playback_buffers
[i
][channelIndex
].stride
956 = playbackSampleSize
* data
->return_playback_channels
;
961 if (audioGroup
->record_stream
!= NULL
) {
962 uint32 recordSampleSize
= audioGroup
->record_stream
->sample_size
;
964 for (int32 i
= 0; i
< data
->return_record_buffers
; i
++) {
965 for (int32 channelIndex
= 0;
966 channelIndex
< data
->return_record_channels
; channelIndex
++) {
967 data
->record_buffers
[i
][channelIndex
].base
968 = (char*)audioGroup
->record_stream
->buffers
[i
]
969 + recordSampleSize
* channelIndex
;
970 data
->record_buffers
[i
][channelIndex
].stride
971 = recordSampleSize
* data
->return_record_channels
;
980 /*! playback_buffer_cycle is the buffer we want to have played */
982 buffer_exchange(hda_audio_group
* audioGroup
, multi_buffer_info
* data
)
986 multi_buffer_info buffer_info
;
988 if (audioGroup
->playback_stream
== NULL
)
991 if (!audioGroup
->playback_stream
->running
) {
992 hda_stream_start(audioGroup
->codec
->controller
,
993 audioGroup
->playback_stream
);
995 if (audioGroup
->record_stream
&& !audioGroup
->record_stream
->running
) {
996 hda_stream_start(audioGroup
->codec
->controller
,
997 audioGroup
->record_stream
);
1001 if (user_memcpy(&buffer_info
, data
, sizeof(buffer_info
)) < B_OK
)
1002 return B_BAD_ADDRESS
;
1004 memcpy(&buffer_info
, data
, sizeof(buffer_info
));
1008 err
= acquire_sem_etc(audioGroup
->codec
->controller
->buffer_ready_sem
,
1009 1, B_CAN_INTERRUPT
, 0);
1011 ERROR("%s: Error waiting for playback buffer to finish (%s)!\n", __func__
,
1016 status
= disable_interrupts();
1017 acquire_spinlock(&audioGroup
->playback_stream
->lock
);
1019 buffer_info
.playback_buffer_cycle
1020 = (audioGroup
->playback_stream
->buffer_cycle
)
1021 % audioGroup
->playback_stream
->num_buffers
;
1022 buffer_info
.played_real_time
= audioGroup
->playback_stream
->real_time
;
1023 buffer_info
.played_frames_count
= audioGroup
->playback_stream
->frames_count
;
1025 release_spinlock(&audioGroup
->playback_stream
->lock
);
1027 if (audioGroup
->record_stream
) {
1028 acquire_spinlock(&audioGroup
->record_stream
->lock
);
1029 buffer_info
.record_buffer_cycle
1030 = (audioGroup
->record_stream
->buffer_cycle
- 1)
1031 % audioGroup
->record_stream
->num_buffers
;
1032 buffer_info
.recorded_real_time
= audioGroup
->record_stream
->real_time
;
1033 buffer_info
.recorded_frames_count
1034 = audioGroup
->record_stream
->frames_count
;
1035 release_spinlock(&audioGroup
->record_stream
->lock
);
1038 restore_interrupts(status
);
1041 if (user_memcpy(data
, &buffer_info
, sizeof(buffer_info
)) < B_OK
)
1042 return B_BAD_ADDRESS
;
1044 memcpy(data
, &buffer_info
, sizeof(buffer_info
));
1048 static int debugBuffersExchanged
= 0;
1050 debugBuffersExchanged
++;
1051 if ((debugBuffersExchanged
% 100) == 1 && debugBuffersExchanged
< 1111)
1052 dprintf("%s: %d buffers processed\n", __func__
, debugBuffersExchanged
);
1059 buffer_force_stop(hda_audio_group
* audioGroup
)
1061 if (audioGroup
->playback_stream
!= NULL
) {
1062 hda_stream_stop(audioGroup
->codec
->controller
,
1063 audioGroup
->playback_stream
);
1065 if (audioGroup
->record_stream
!= NULL
) {
1066 hda_stream_stop(audioGroup
->codec
->controller
,
1067 audioGroup
->record_stream
);
1075 multi_audio_control(void* cookie
, uint32 op
, void* arg
, size_t len
)
1077 hda_codec
* codec
= (hda_codec
*)cookie
;
1078 hda_audio_group
* audioGroup
;
1080 /* FIXME: We should simply pass the audioGroup into here... */
1081 if (!codec
|| codec
->num_audio_groups
== 0)
1084 audioGroup
= codec
->audio_groups
[0];
1086 // TODO: make userland-safe when built for Haiku!
1089 case B_MULTI_GET_DESCRIPTION
:
1092 multi_description description
;
1093 multi_channel_info channels
[16];
1094 multi_channel_info
* originalChannels
;
1096 if (user_memcpy(&description
, arg
, sizeof(multi_description
))
1098 return B_BAD_ADDRESS
;
1100 originalChannels
= description
.channels
;
1101 description
.channels
= channels
;
1102 if (description
.request_channel_count
> 16)
1103 description
.request_channel_count
= 16;
1105 status_t status
= get_description(audioGroup
, &description
);
1109 description
.channels
= originalChannels
;
1110 if (user_memcpy(arg
, &description
, sizeof(multi_description
))
1112 return B_BAD_ADDRESS
;
1113 return user_memcpy(originalChannels
, channels
,
1114 sizeof(multi_channel_info
) * description
.request_channel_count
);
1116 return get_description(audioGroup
, (multi_description
*)arg
);
1120 case B_MULTI_GET_ENABLED_CHANNELS
:
1121 return get_enabled_channels(audioGroup
, (multi_channel_enable
*)arg
);
1122 case B_MULTI_SET_ENABLED_CHANNELS
:
1125 case B_MULTI_GET_GLOBAL_FORMAT
:
1126 return get_global_format(audioGroup
, (multi_format_info
*)arg
);
1127 case B_MULTI_SET_GLOBAL_FORMAT
:
1128 return set_global_format(audioGroup
, (multi_format_info
*)arg
);
1130 case B_MULTI_LIST_MIX_CHANNELS
:
1131 return list_mix_channels(audioGroup
, (multi_mix_channel_info
*)arg
);
1132 case B_MULTI_LIST_MIX_CONTROLS
:
1133 return list_mix_controls(audioGroup
, (multi_mix_control_info
*)arg
);
1134 case B_MULTI_LIST_MIX_CONNECTIONS
:
1135 return list_mix_connections(audioGroup
,
1136 (multi_mix_connection_info
*)arg
);
1137 case B_MULTI_GET_MIX
:
1138 return get_mix(audioGroup
, (multi_mix_value_info
*)arg
);
1139 case B_MULTI_SET_MIX
:
1140 return set_mix(audioGroup
, (multi_mix_value_info
*)arg
);
1142 case B_MULTI_GET_BUFFERS
:
1143 return get_buffers(audioGroup
, (multi_buffer_list
*)arg
);
1145 case B_MULTI_BUFFER_EXCHANGE
:
1146 return buffer_exchange(audioGroup
, (multi_buffer_info
*)arg
);
1147 case B_MULTI_BUFFER_FORCE_STOP
:
1148 return buffer_force_stop(audioGroup
);
1150 case B_MULTI_GET_EVENT_INFO
:
1151 case B_MULTI_SET_EVENT_INFO
:
1152 case B_MULTI_GET_EVENT
:
1153 case B_MULTI_GET_CHANNEL_FORMATS
:
1154 case B_MULTI_SET_CHANNEL_FORMATS
:
1155 case B_MULTI_SET_BUFFERS
:
1156 case B_MULTI_SET_START_TIME
: