2 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
3 * Distributed under the terms of the MIT License.
7 //! Media add-on for drivers that use the multi audio interface
10 #include "MultiAudioNode.h"
17 #include <BufferGroup.h>
19 #include <ParameterWeb.h>
22 #include <Referenceable.h>
24 #include "MultiAudioUtility.h"
29 #include "Resampler.h"
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "MultiAudio"
34 #define PARAMETER_ID_INPUT_FREQUENCY 1
35 #define PARAMETER_ID_OUTPUT_FREQUENCY 2
38 //This represent an hardware output
41 node_input(media_input
& input
, media_format format
);
46 media_format fPreferredFormat
;
48 volatile uint32 fBufferCycle
;
49 multi_buffer_info fOldBufferInfo
;
51 Resampler
*fResampler
;
55 //This represent an hardware input
58 node_output(media_output
& output
, media_format format
);
63 media_format fPreferredFormat
;
66 BBufferGroup
* fBufferGroup
;
69 volatile uint32 fBufferCycle
;
70 multi_buffer_info fOldBufferInfo
;
71 Resampler
* fResampler
;
75 struct FrameRateChangeCookie
: public BReferenceable
{
81 struct sample_rate_info
{
82 uint32 multiAudioRate
;
87 static const sample_rate_info kSampleRateInfos
[] = {
89 {B_SR_11025
, "11025"},
90 {B_SR_12000
, "12000"},
91 {B_SR_16000
, "16000"},
92 {B_SR_22050
, "22050"},
93 {B_SR_24000
, "24000"},
94 {B_SR_32000
, "32000"},
95 {B_SR_44100
, "44100"},
96 {B_SR_48000
, "48000"},
97 {B_SR_64000
, "64000"},
98 {B_SR_88200
, "88200"},
99 {B_SR_96000
, "96000"},
100 {B_SR_176400
, "176400"},
101 {B_SR_192000
, "192000"},
102 {B_SR_384000
, "384000"},
103 {B_SR_1536000
, "1536000"},
108 const char* kMultiControlString
[] = {
110 B_TRANSLATE("Output"), B_TRANSLATE("Input"), B_TRANSLATE("Setup"),
111 B_TRANSLATE("Tone control"), B_TRANSLATE("Extended Setup"),
112 B_TRANSLATE("Enhanced Setup"), B_TRANSLATE("Master"), B_TRANSLATE("Beep"),
113 B_TRANSLATE("Phone"), B_TRANSLATE("Mic"), B_TRANSLATE("Line"),
114 B_TRANSLATE("CD"), B_TRANSLATE("Video"), B_TRANSLATE("Aux"),
115 B_TRANSLATE("Wave"), B_TRANSLATE("Gain"), B_TRANSLATE("Level"),
116 B_TRANSLATE("Volume"), B_TRANSLATE("Mute"), B_TRANSLATE("Enable"),
117 B_TRANSLATE("Stereo mix"), B_TRANSLATE("Mono mix"),
118 B_TRANSLATE("Output stereo mix"), B_TRANSLATE("Output mono mix"),
119 B_TRANSLATE("Output bass"), B_TRANSLATE("Output treble"),
120 B_TRANSLATE("Output 3D center"), B_TRANSLATE("Output 3D depth"),
121 B_TRANSLATE("Headphones"), B_TRANSLATE("SPDIF")
128 node_input::node_input(media_input
& input
, media_format format
)
132 fPreferredFormat
= format
;
139 node_input::~node_input()
148 node_output::node_output(media_output
& output
, media_format format
)
155 fPreferredFormat
= format
;
161 node_output::~node_output()
170 MultiAudioNode::MultiAudioNode(BMediaAddOn
* addon
, const char* name
,
171 MultiAudioDevice
* device
, int32 internalID
, BMessage
* config
)
174 BBufferConsumer(B_MEDIA_RAW_AUDIO
),
175 BBufferProducer(B_MEDIA_RAW_AUDIO
),
177 fBufferLock("multi audio buffers"),
181 fTimeSourceStarted(false),
186 fInitStatus
= B_NO_INIT
;
194 AddNodeKind(B_PHYSICAL_OUTPUT
);
195 AddNodeKind(B_PHYSICAL_INPUT
);
197 // initialize our preferred format objects
198 memset(&fOutputPreferredFormat
, 0, sizeof(fOutputPreferredFormat
));
199 // set everything to wildcard first
200 fOutputPreferredFormat
.type
= B_MEDIA_RAW_AUDIO
;
201 fOutputPreferredFormat
.u
.raw_audio
.format
202 = MultiAudio::convert_to_media_format(
203 fDevice
->FormatInfo().output
.format
);
204 fOutputPreferredFormat
.u
.raw_audio
.valid_bits
205 = MultiAudio::convert_to_valid_bits(
206 fDevice
->FormatInfo().output
.format
);
207 fOutputPreferredFormat
.u
.raw_audio
.channel_count
= 2;
208 fOutputPreferredFormat
.u
.raw_audio
.frame_rate
209 = MultiAudio::convert_to_sample_rate(fDevice
->FormatInfo().output
.rate
);
211 fOutputPreferredFormat
.u
.raw_audio
.byte_order
= B_MEDIA_HOST_ENDIAN
;
213 // we'll use the consumer's preferred buffer size, if any
214 fOutputPreferredFormat
.u
.raw_audio
.buffer_size
215 = fDevice
->BufferList().return_playback_buffer_size
216 * (fOutputPreferredFormat
.u
.raw_audio
.format
217 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
218 * fOutputPreferredFormat
.u
.raw_audio
.channel_count
;
220 // initialize our preferred format objects
221 memset(&fInputPreferredFormat
, 0, sizeof(fInputPreferredFormat
));
222 // set everything to wildcard first
223 fInputPreferredFormat
.type
= B_MEDIA_RAW_AUDIO
;
224 fInputPreferredFormat
.u
.raw_audio
.format
225 = MultiAudio::convert_to_media_format(
226 fDevice
->FormatInfo().input
.format
);
227 fInputPreferredFormat
.u
.raw_audio
.valid_bits
228 = MultiAudio::convert_to_valid_bits(fDevice
->FormatInfo().input
.format
);
229 fInputPreferredFormat
.u
.raw_audio
.channel_count
= 2;
230 fInputPreferredFormat
.u
.raw_audio
.frame_rate
231 = MultiAudio::convert_to_sample_rate(fDevice
->FormatInfo().input
.rate
); // measured in Hertz
232 fInputPreferredFormat
.u
.raw_audio
.byte_order
= B_MEDIA_HOST_ENDIAN
;
234 // we'll use the consumer's preferred buffer size, if any
235 fInputPreferredFormat
.u
.raw_audio
.buffer_size
236 = fDevice
->BufferList().return_record_buffer_size
237 * (fInputPreferredFormat
.u
.raw_audio
.format
238 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
239 * fInputPreferredFormat
.u
.raw_audio
.channel_count
;
241 if (config
!= NULL
) {
243 PRINT_OBJECT(*config
);
250 MultiAudioNode::~MultiAudioNode()
253 fAddOn
->GetConfigurationFor(this, NULL
);
256 BMediaEventLooper::Quit();
261 MultiAudioNode::InitCheck() const
269 MultiAudioNode::GetFlavor(flavor_info
* info
, int32 id
)
275 info
->flavor_flags
= 0;
276 info
->possible_count
= 1;
277 // one flavor at a time
278 info
->in_format_count
= 0;
280 info
->in_formats
= 0;
281 info
->out_format_count
= 0;
283 info
->out_formats
= 0;
284 info
->internal_id
= id
;
286 info
->name
= const_cast<char*>("MultiAudioNode Node");
287 info
->info
= const_cast<char*>("The MultiAudioNode node outputs to "
288 "multi_audio drivers.");
289 info
->kinds
= B_BUFFER_CONSUMER
| B_BUFFER_PRODUCER
| B_TIME_SOURCE
290 | B_PHYSICAL_OUTPUT
| B_PHYSICAL_INPUT
| B_CONTROLLABLE
;
291 info
->in_format_count
= 1;
293 media_format
* inFormats
= new media_format
[info
->in_format_count
];
294 GetFormat(&inFormats
[0]);
295 info
->in_formats
= inFormats
;
297 info
->out_format_count
= 1;
299 media_format
* outFormats
= new media_format
[info
->out_format_count
];
300 GetFormat(&outFormats
[0]);
301 info
->out_formats
= outFormats
;
306 MultiAudioNode::GetFormat(media_format
* format
)
312 format
->type
= B_MEDIA_RAW_AUDIO
;
313 format
->require_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
314 format
->deny_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
315 format
->u
.raw_audio
= media_raw_audio_format::wildcard
;
319 //#pragma mark - BMediaNode
323 MultiAudioNode::AddOn(int32
* _internalID
) const
326 // BeBook says this only gets called if we were in an add-on.
327 if (fAddOn
!= 0 && _internalID
!= NULL
)
335 MultiAudioNode::Preroll()
338 // TODO: Performance opportunity
339 BMediaNode::Preroll();
344 MultiAudioNode::HandleMessage(int32 message
, const void* data
, size_t size
)
352 MultiAudioNode::NodeRegistered()
356 if (fInitStatus
!= B_OK
) {
357 ReportError(B_NODE_IN_DISTRESS
);
361 node_input
*currentInput
= NULL
;
364 for (int32 i
= 0; i
< fDevice
->Description().output_channel_count
; i
++) {
365 if (currentInput
== NULL
366 || (fDevice
->Description().channels
[i
].designations
367 & B_CHANNEL_MONO_BUS
) != 0
368 || ((fDevice
->Description().channels
[currentId
].designations
369 & B_CHANNEL_STEREO_BUS
) != 0
370 && ((fDevice
->Description().channels
[i
].designations
371 & B_CHANNEL_LEFT
) != 0
372 || (fDevice
->Description().channels
[i
].designations
373 & B_CHANNEL_STEREO_BUS
) == 0))
374 || ((fDevice
->Description().channels
[currentId
].designations
375 & B_CHANNEL_SURROUND_BUS
) != 0
376 && ((fDevice
->Description().channels
[i
].designations
377 & B_CHANNEL_LEFT
) != 0
378 || (fDevice
->Description().channels
[i
].designations
379 & B_CHANNEL_SURROUND_BUS
) == 0))) {
380 PRINT(("NodeRegistered(): creating an input for %" B_PRIi32
"\n",
382 PRINT(("%" B_PRId32
"\t%d\t0x%" B_PRIx32
"\t0x%" B_PRIx32
"\n",
383 fDevice
->Description().channels
[i
].channel_id
,
384 fDevice
->Description().channels
[i
].kind
,
385 fDevice
->Description().channels
[i
].designations
,
386 fDevice
->Description().channels
[i
].connectors
));
388 media_input
* input
= new media_input
;
390 input
->format
= fOutputPreferredFormat
;
391 input
->destination
.port
= ControlPort();
392 input
->destination
.id
= fInputs
.CountItems();
393 input
->node
= Node();
394 sprintf(input
->name
, "output %" B_PRId32
, input
->destination
.id
);
396 currentInput
= new node_input(*input
, fOutputPreferredFormat
);
397 currentInput
->fPreferredFormat
.u
.raw_audio
.channel_count
= 1;
398 currentInput
->fInput
.format
= currentInput
->fPreferredFormat
;
399 delete currentInput
->fResampler
;
400 currentInput
->fResampler
= new
401 Resampler(currentInput
->fPreferredFormat
.AudioFormat(),
402 fOutputPreferredFormat
.AudioFormat());
404 currentInput
->fChannelId
405 = fDevice
->Description().channels
[i
].channel_id
;
406 fInputs
.AddItem(currentInput
);
410 PRINT(("NodeRegistered(): adding a channel\n"));
411 currentInput
->fPreferredFormat
.u
.raw_audio
.channel_count
++;
412 currentInput
->fInput
.format
= currentInput
->fPreferredFormat
;
414 currentInput
->fInput
.format
.u
.raw_audio
.format
415 = media_raw_audio_format::wildcard
.format
;
418 node_output
*currentOutput
= NULL
;
421 for (int32 i
= fDevice
->Description().output_channel_count
;
422 i
< fDevice
->Description().output_channel_count
423 + fDevice
->Description().input_channel_count
; i
++) {
424 if (currentOutput
== NULL
425 || (fDevice
->Description().channels
[i
].designations
426 & B_CHANNEL_MONO_BUS
) != 0
427 || ((fDevice
->Description().channels
[currentId
].designations
428 & B_CHANNEL_STEREO_BUS
) != 0
429 && ((fDevice
->Description().channels
[i
].designations
430 & B_CHANNEL_LEFT
) != 0
431 || (fDevice
->Description().channels
[i
].designations
432 & B_CHANNEL_STEREO_BUS
) == 0))
433 || ((fDevice
->Description().channels
[currentId
].designations
434 & B_CHANNEL_SURROUND_BUS
) != 0
435 && ((fDevice
->Description().channels
[i
].designations
436 & B_CHANNEL_LEFT
) != 0
437 || (fDevice
->Description().channels
[i
].designations
438 & B_CHANNEL_SURROUND_BUS
) == 0))) {
439 PRINT(("NodeRegistered(): creating an output for %" B_PRIi32
"\n",
441 PRINT(("%" B_PRId32
"\t%d\t0x%" B_PRIx32
"\t0x%" B_PRIx32
"\n",
442 fDevice
->Description().channels
[i
].channel_id
,
443 fDevice
->Description().channels
[i
].kind
,
444 fDevice
->Description().channels
[i
].designations
,
445 fDevice
->Description().channels
[i
].connectors
));
447 media_output
*output
= new media_output
;
449 output
->format
= fInputPreferredFormat
;
450 output
->destination
= media_destination::null
;
451 output
->source
.port
= ControlPort();
452 output
->source
.id
= fOutputs
.CountItems();
453 output
->node
= Node();
454 sprintf(output
->name
, "input %" B_PRId32
, output
->source
.id
);
456 currentOutput
= new node_output(*output
, fInputPreferredFormat
);
457 currentOutput
->fPreferredFormat
.u
.raw_audio
.channel_count
= 1;
458 currentOutput
->fOutput
.format
= currentOutput
->fPreferredFormat
;
459 delete currentOutput
->fResampler
;
460 currentOutput
->fResampler
= new
461 Resampler(fInputPreferredFormat
.AudioFormat(),
462 currentOutput
->fPreferredFormat
.AudioFormat());
464 currentOutput
->fChannelId
465 = fDevice
->Description().channels
[i
].channel_id
;
466 fOutputs
.AddItem(currentOutput
);
470 PRINT(("NodeRegistered(): adding a channel\n"));
471 currentOutput
->fPreferredFormat
.u
.raw_audio
.channel_count
++;
472 currentOutput
->fOutput
.format
= currentOutput
->fPreferredFormat
;
476 // Set up our parameter web
477 fWeb
= MakeParameterWeb();
478 SetParameterWeb(fWeb
);
480 // Apply configuration
482 bigtime_t start
= system_time();
486 int32 parameterID
= 0;
489 while (fConfig
.FindInt32("parameterID", index
, ¶meterID
) == B_OK
) {
490 if (fConfig
.FindData("parameterData", B_RAW_TYPE
, index
, &data
, &size
)
492 SetParameterValue(parameterID
, TimeSource()->Now(), data
, size
);
497 PRINT(("apply configuration in: %" B_PRIdBIGTIME
"\n",
498 system_time() - start
));
500 SetPriority(B_REAL_TIME_PRIORITY
);
506 MultiAudioNode::RequestCompleted(const media_request_info
& info
)
510 if (info
.what
!= media_request_info::B_REQUEST_FORMAT_CHANGE
)
513 FrameRateChangeCookie
* cookie
514 = (FrameRateChangeCookie
*)info
.user_data
;
518 BReference
<FrameRateChangeCookie
> cookieReference(cookie
, true);
520 // if the request failed, we reset the frame rate
521 if (info
.status
!= B_OK
) {
522 if (cookie
->id
== PARAMETER_ID_INPUT_FREQUENCY
) {
523 _SetNodeInputFrameRate(cookie
->oldFrameRate
);
524 if (fDevice
->Description().output_rates
& B_SR_SAME_AS_INPUT
)
525 _SetNodeOutputFrameRate(cookie
->oldFrameRate
);
526 } else if (cookie
->id
== PARAMETER_ID_OUTPUT_FREQUENCY
)
527 _SetNodeOutputFrameRate(cookie
->oldFrameRate
);
529 // TODO: If we have multiple connections, we should request to change
538 MultiAudioNode::SetTimeSource(BTimeSource
* timeSource
)
544 // #pragma mark - BBufferConsumer
548 MultiAudioNode::AcceptFormat(const media_destination
& dest
,
549 media_format
* format
)
551 // Check to make sure the format is okay, then remove
552 // any wildcards corresponding to our requirements.
557 if (format
->type
!= B_MEDIA_RAW_AUDIO
)
558 return B_MEDIA_BAD_FORMAT
;
560 node_input
*channel
= _FindInput(dest
);
562 return B_MEDIA_BAD_DESTINATION
;
564 /* media_format * myFormat = GetFormat();
565 fprintf(stderr,"proposed format: ");
566 print_media_format(format);
567 fprintf(stderr,"\n");
568 fprintf(stderr,"my format: ");
569 print_media_format(myFormat);
570 fprintf(stderr,"\n");*/
571 // Be's format_is_compatible doesn't work.
572 // if (!format_is_compatible(*format,*myFormat)) {
574 channel
->fFormat
= channel
->fPreferredFormat
;
576 /*if(format->u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT
577 && channel->fPreferredFormat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT)
578 format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
580 format
->u
.raw_audio
.format
= channel
->fPreferredFormat
.u
.raw_audio
.format
;
581 format
->u
.raw_audio
.valid_bits
582 = channel
->fPreferredFormat
.u
.raw_audio
.valid_bits
;
584 format
->u
.raw_audio
.frame_rate
585 = channel
->fPreferredFormat
.u
.raw_audio
.frame_rate
;
586 format
->u
.raw_audio
.channel_count
587 = channel
->fPreferredFormat
.u
.raw_audio
.channel_count
;
588 format
->u
.raw_audio
.byte_order
= B_MEDIA_HOST_ENDIAN
;
589 format
->u
.raw_audio
.buffer_size
590 = fDevice
->BufferList().return_playback_buffer_size
591 * (format
->u
.raw_audio
.format
592 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
593 * format
->u
.raw_audio
.channel_count
;
595 /*media_format myFormat;
596 GetFormat(&myFormat);
597 if (!format_is_acceptible(*format,myFormat)) {
598 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
599 return B_MEDIA_BAD_FORMAT;
601 //AddRequirements(format);
607 MultiAudioNode::GetNextInput(int32
* cookie
, media_input
* _input
)
613 if (*cookie
>= fInputs
.CountItems() || *cookie
< 0)
616 node_input
* channel
= (node_input
*)fInputs
.ItemAt(*cookie
);
617 *_input
= channel
->fInput
;
619 PRINT(("input.format: %" B_PRIu32
"\n",
620 channel
->fInput
.format
.u
.raw_audio
.format
));
626 MultiAudioNode::DisposeInputCookie(int32 cookie
)
629 // nothing to do since our cookies are just integers
634 MultiAudioNode::BufferReceived(BBuffer
* buffer
)
637 switch (buffer
->Header()->type
) {
638 /*case B_MEDIA_PARAMETERS:
640 status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
641 if (status != B_OK) {
642 fprintf(stderr,"ApplyParameterData in MultiAudioNode::BufferReceived failed\n");
647 case B_MEDIA_RAW_AUDIO
:
648 if ((buffer
->Flags() & BBuffer::B_SMALL_BUFFER
) != 0) {
649 fprintf(stderr
, "NOT IMPLEMENTED: B_SMALL_BUFFER in "
650 "MultiAudioNode::BufferReceived\n");
651 // TODO: implement this part
654 media_timed_event
event(buffer
->Header()->start_time
,
655 BTimedEventQueue::B_HANDLE_BUFFER
, buffer
,
656 BTimedEventQueue::B_RECYCLE_BUFFER
);
657 status_t status
= EventQueue()->AddEvent(event
);
658 if (status
!= B_OK
) {
659 fprintf(stderr
, "EventQueue()->AddEvent(event) in "
660 "MultiAudioNode::BufferReceived failed\n");
666 fprintf(stderr
, "unexpected buffer type in "
667 "MultiAudioNode::BufferReceived\n");
675 MultiAudioNode::ProducerDataStatus(const media_destination
& forWhom
,
676 int32 status
, bigtime_t atPerformanceTime
)
678 node_input
* channel
= _FindInput(forWhom
);
679 if (channel
== NULL
) {
680 fprintf(stderr
, "invalid destination received in "
681 "MultiAudioNode::ProducerDataStatus\n");
685 media_timed_event
event(atPerformanceTime
, BTimedEventQueue::B_DATA_STATUS
,
686 &channel
->fInput
, BTimedEventQueue::B_NO_CLEANUP
, status
, 0, NULL
);
687 EventQueue()->AddEvent(event
);
692 MultiAudioNode::GetLatencyFor(const media_destination
& forWhom
,
693 bigtime_t
* _latency
, media_node_id
* _timeSource
)
696 if (_latency
== NULL
|| _timeSource
== NULL
)
699 node_input
* channel
= _FindInput(forWhom
);
701 return B_MEDIA_BAD_DESTINATION
;
703 *_latency
= EventLatency();
704 *_timeSource
= TimeSource()->ID();
710 MultiAudioNode::Connected(const media_source
& producer
,
711 const media_destination
& where
, const media_format
& with_format
,
712 media_input
* out_input
)
715 if (out_input
== 0) {
716 fprintf(stderr
, "<- B_BAD_VALUE\n");
720 node_input
* channel
= _FindInput(where
);
721 if (channel
== NULL
) {
722 fprintf(stderr
, "<- B_MEDIA_BAD_DESTINATION\n");
723 return B_MEDIA_BAD_DESTINATION
;
726 _UpdateInternalLatency(with_format
);
728 // record the agreed upon values
729 channel
->fInput
.source
= producer
;
730 channel
->fInput
.format
= with_format
;
731 *out_input
= channel
->fInput
;
733 _StartOutputThreadIfNeeded();
740 MultiAudioNode::Disconnected(const media_source
& producer
,
741 const media_destination
& where
)
745 node_input
* channel
= _FindInput(where
);
746 if (channel
== NULL
|| channel
->fInput
.source
!= producer
)
749 channel
->fInput
.source
= media_source::null
;
750 channel
->fInput
.format
= channel
->fPreferredFormat
;
752 BAutolock
locker(fBufferLock
);
753 _FillWithZeros(*channel
);
754 //GetFormat(&channel->fInput.format);
759 MultiAudioNode::FormatChanged(const media_source
& producer
,
760 const media_destination
& consumer
, int32 change_tag
,
761 const media_format
& format
)
765 node_input
* channel
= _FindInput(consumer
);
768 fprintf(stderr
, "<- B_MEDIA_BAD_DESTINATION\n");
769 return B_MEDIA_BAD_DESTINATION
;
771 if (channel
->fInput
.source
!= producer
)
772 return B_MEDIA_BAD_SOURCE
;
779 MultiAudioNode::SeekTagRequested(const media_destination
& destination
,
780 bigtime_t targetTime
, uint32 flags
, media_seek_tag
* _seekTag
,
781 bigtime_t
* _taggedTime
, uint32
* _flags
)
784 return BBufferConsumer::SeekTagRequested(destination
, targetTime
, flags
,
785 _seekTag
, _taggedTime
, _flags
);
789 // #pragma mark - BBufferProducer
793 MultiAudioNode::FormatSuggestionRequested(media_type type
, int32
/*quality*/,
794 media_format
* format
)
796 // FormatSuggestionRequested() is not necessarily part of the format
797 // negotiation process; it's simply an interrogation -- the caller
798 // wants to see what the node's preferred data format is, given a
799 // suggestion by the caller.
802 if (format
== NULL
) {
803 fprintf(stderr
, "\tERROR - NULL format pointer passed in!\n");
807 // this is the format we'll be returning (our preferred format)
808 *format
= fInputPreferredFormat
;
810 // a wildcard type is okay; we can specialize it
811 if (type
== B_MEDIA_UNKNOWN_TYPE
)
812 type
= B_MEDIA_RAW_AUDIO
;
814 // we only support raw audio
815 if (type
!= B_MEDIA_RAW_AUDIO
)
816 return B_MEDIA_BAD_FORMAT
;
823 MultiAudioNode::FormatProposal(const media_source
& output
, media_format
* format
)
825 // FormatProposal() is the first stage in the BMediaRoster::Connect()
826 // process. We hand out a suggested format, with wildcards for any
827 // variations we support.
830 // is this a proposal for our select output?
831 node_output
* channel
= _FindOutput(output
);
832 if (channel
== NULL
) {
833 fprintf(stderr
, "MultiAudioNode::FormatProposal returning "
834 "B_MEDIA_BAD_SOURCE\n");
835 return B_MEDIA_BAD_SOURCE
;
838 // We only support floating-point raw audio, so we always return that,
839 // but we supply an error code depending on whether we found the proposal
841 media_type requestedType
= format
->type
;
842 *format
= channel
->fPreferredFormat
;
843 if (requestedType
!= B_MEDIA_UNKNOWN_TYPE
844 && requestedType
!= B_MEDIA_RAW_AUDIO
) {
845 fprintf(stderr
, "MultiAudioNode::FormatProposal returning "
846 "B_MEDIA_BAD_FORMAT\n");
847 return B_MEDIA_BAD_FORMAT
;
849 // raw audio or wildcard type, either is okay by us
855 MultiAudioNode::FormatChangeRequested(const media_source
& source
,
856 const media_destination
& destination
, media_format
* format
,
861 // we don't support any other formats, so we just reject any format changes.
867 MultiAudioNode::GetNextOutput(int32
* cookie
, media_output
* _output
)
871 if (*cookie
< fOutputs
.CountItems() && *cookie
>= 0) {
872 node_output
* channel
= (node_output
*)fOutputs
.ItemAt(*cookie
);
873 *_output
= channel
->fOutput
;
882 MultiAudioNode::DisposeOutputCookie(int32 cookie
)
885 // do nothing because we don't use the cookie for anything special
891 MultiAudioNode::SetBufferGroup(const media_source
& forSource
,
892 BBufferGroup
* newGroup
)
896 // is this our output?
897 node_output
* channel
= _FindOutput(forSource
);
898 if (channel
== NULL
) {
899 fprintf(stderr
, "MultiAudioNode::SetBufferGroup returning "
900 "B_MEDIA_BAD_SOURCE\n");
901 return B_MEDIA_BAD_SOURCE
;
904 // Are we being passed the buffer group we're already using?
905 if (newGroup
== channel
->fBufferGroup
)
908 // Ahh, someone wants us to use a different buffer group. At this point
909 // we delete the one we are using and use the specified one instead.
910 // If the specified group is NULL, we need to recreate one ourselves, and
911 // use *that*. Note that if we're caching a BBuffer that we requested
912 // earlier, we have to Recycle() that buffer *before* deleting the buffer
913 // group, otherwise we'll deadlock waiting for that buffer to be recycled!
914 delete channel
->fBufferGroup
;
915 // waits for all buffers to recycle
916 if (newGroup
!= NULL
) {
917 // we were given a valid group; just use that one from now on
918 channel
->fBufferGroup
= newGroup
;
920 // we were passed a NULL group pointer; that means we construct
921 // our own buffer group to use from now on
922 size_t size
= channel
->fOutput
.format
.u
.raw_audio
.buffer_size
;
923 int32 count
= int32(fLatency
/ BufferDuration() + 1 + 1);
924 BBufferGroup
* group
= new BBufferGroup(size
, count
);
925 if (group
== NULL
|| group
->InitCheck() != B_OK
) {
927 fprintf(stderr
, "MultiAudioNode::SetBufferGroup failed to"
928 "instantiate a new group.\n");
931 channel
->fBufferGroup
= group
;
939 MultiAudioNode::PrepareToConnect(const media_source
& what
,
940 const media_destination
& where
, media_format
* format
,
941 media_source
* source
, char* name
)
945 // is this our output?
946 node_output
* channel
= _FindOutput(what
);
947 if (channel
== NULL
) {
948 fprintf(stderr
, "MultiAudioNode::PrepareToConnect returning "
949 "B_MEDIA_BAD_SOURCE\n");
950 return B_MEDIA_BAD_SOURCE
;
953 // are we already connected?
954 if (channel
->fOutput
.destination
!= media_destination::null
)
955 return B_MEDIA_ALREADY_CONNECTED
;
957 // the format may not yet be fully specialized (the consumer might have
958 // passed back some wildcards). Finish specializing it now, and return an
959 // error if we don't support the requested format.
960 if (format
->type
!= B_MEDIA_RAW_AUDIO
) {
961 fprintf(stderr
, "\tnon-raw-audio format?!\n");
962 return B_MEDIA_BAD_FORMAT
;
965 // !!! validate all other fields except for buffer_size here, because the
966 // consumer might have supplied different values from AcceptFormat()?
968 // check the buffer size, which may still be wildcarded
969 if (format
->u
.raw_audio
.buffer_size
970 == media_raw_audio_format::wildcard
.buffer_size
) {
971 format
->u
.raw_audio
.buffer_size
= 2048;
972 // pick something comfortable to suggest
973 fprintf(stderr
, "\tno buffer size provided, suggesting %lu\n",
974 format
->u
.raw_audio
.buffer_size
);
976 fprintf(stderr
, "\tconsumer suggested buffer_size %lu\n",
977 format
->u
.raw_audio
.buffer_size
);
980 // Now reserve the connection, and return information about it
981 channel
->fOutput
.destination
= where
;
982 channel
->fOutput
.format
= *format
;
984 *source
= channel
->fOutput
.source
;
985 strlcpy(name
, channel
->fOutput
.name
, B_MEDIA_NAME_LENGTH
);
991 MultiAudioNode::Connect(status_t error
, const media_source
& source
,
992 const media_destination
& destination
, const media_format
& format
,
997 // is this our output?
998 node_output
* channel
= _FindOutput(source
);
999 if (channel
== NULL
) {
1000 fprintf(stderr
, "MultiAudioNode::Connect returning (cause: "
1001 "B_MEDIA_BAD_SOURCE)\n");
1005 // If something earlier failed, Connect() might still be called, but with
1006 // a non-zero error code. When that happens we simply unreserve the
1007 // connection and do nothing else.
1008 if (error
!= B_OK
) {
1009 channel
->fOutput
.destination
= media_destination::null
;
1010 channel
->fOutput
.format
= channel
->fPreferredFormat
;
1014 // Okay, the connection has been confirmed. Record the destination and
1015 // format that we agreed on, and report our connection name again.
1016 channel
->fOutput
.destination
= destination
;
1017 channel
->fOutput
.format
= format
;
1018 strlcpy(name
, channel
->fOutput
.name
, B_MEDIA_NAME_LENGTH
);
1020 // reset our buffer duration, etc. to avoid later calculations
1021 bigtime_t duration
= channel
->fOutput
.format
.u
.raw_audio
.buffer_size
* 10000
1022 / ((channel
->fOutput
.format
.u
.raw_audio
.format
1023 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
1024 * channel
->fOutput
.format
.u
.raw_audio
.channel_count
)
1025 / ((int32
)(channel
->fOutput
.format
.u
.raw_audio
.frame_rate
/ 100));
1027 SetBufferDuration(duration
);
1029 // Now that we're connected, we can determine our downstream latency.
1030 // Do so, then make sure we get our events early enough.
1032 FindLatencyFor(channel
->fOutput
.destination
, &fLatency
, &id
);
1033 PRINT(("\tdownstream latency = %" B_PRIdBIGTIME
"\n", fLatency
));
1035 fInternalLatency
= BufferDuration();
1036 PRINT(("\tbuffer-filling took %" B_PRIdBIGTIME
" usec on this machine\n",
1038 //SetEventLatency(fLatency + fInternalLatency);
1040 // Set up the buffer group for our connection, as long as nobody handed us
1041 // a buffer group (via SetBufferGroup()) prior to this. That can happen,
1042 // for example, if the consumer calls SetOutputBuffersFor() on us from
1043 // within its Connected() method.
1044 if (channel
->fBufferGroup
== NULL
)
1045 _AllocateBuffers(*channel
);
1047 _StartOutputThreadIfNeeded();
1052 MultiAudioNode::Disconnect(const media_source
& what
,
1053 const media_destination
& where
)
1057 // is this our output?
1058 node_output
* channel
= _FindOutput(what
);
1059 if (channel
== NULL
) {
1060 fprintf(stderr
, "MultiAudioNode::Disconnect() returning (cause: "
1061 "B_MEDIA_BAD_SOURCE)\n");
1065 // Make sure that our connection is the one being disconnected
1066 if (where
== channel
->fOutput
.destination
1067 && what
== channel
->fOutput
.source
) {
1068 channel
->fOutput
.destination
= media_destination::null
;
1069 channel
->fOutput
.format
= channel
->fPreferredFormat
;
1070 delete channel
->fBufferGroup
;
1071 channel
->fBufferGroup
= NULL
;
1073 fprintf(stderr
, "\tDisconnect() called with wrong source/destination ("
1074 "%" B_PRId32
"/%" B_PRId32
"), ours is (%" B_PRId32
"/%" B_PRId32
1075 ")\n", what
.id
, where
.id
, channel
->fOutput
.source
.id
,
1076 channel
->fOutput
.destination
.id
);
1082 MultiAudioNode::LateNoticeReceived(const media_source
& what
, bigtime_t howMuch
,
1083 bigtime_t performanceTime
)
1087 // is this our output?
1088 node_output
* channel
= _FindOutput(what
);
1089 if (channel
== NULL
)
1092 // If we're late, we need to catch up. Respond in a manner appropriate
1093 // to our current run mode.
1094 if (RunMode() == B_RECORDING
) {
1095 // A hardware capture node can't adjust; it simply emits buffers at
1096 // appropriate points. We (partially) simulate this by not adjusting
1097 // our behavior upon receiving late notices -- after all, the hardware
1098 // can't choose to capture "sooner"....
1099 } else if (RunMode() == B_INCREASE_LATENCY
) {
1100 // We're late, and our run mode dictates that we try to produce buffers
1101 // earlier in order to catch up. This argues that the downstream nodes
1102 // are not properly reporting their latency, but there's not much we can
1103 // do about that at the moment, so we try to start producing buffers
1104 // earlier to compensate.
1105 fInternalLatency
+= howMuch
;
1106 SetEventLatency(fLatency
+ fInternalLatency
);
1108 fprintf(stderr
, "\tincreasing latency to %" B_PRIdBIGTIME
"\n",
1109 fLatency
+ fInternalLatency
);
1111 // The other run modes dictate various strategies for sacrificing data
1112 // quality in the interests of timely data delivery. The way *we* do
1113 // this is to skip a buffer, which catches us up in time by one buffer
1115 /*size_t nSamples = fOutput.format.u.raw_audio.buffer_size / sizeof(float);
1116 mSamplesSent += nSamples;*/
1118 fprintf(stderr
, "\tskipping a buffer to try to catch up\n");
1124 MultiAudioNode::EnableOutput(const media_source
& what
, bool enabled
,
1125 int32
* _deprecated_
)
1129 // If I had more than one output, I'd have to walk my list of output
1130 // records to see which one matched the given source, and then
1131 // enable/disable that one. But this node only has one output, so I
1132 // just make sure the given source matches, then set the enable state
1134 node_output
* channel
= _FindOutput(what
);
1135 if (channel
!= NULL
)
1136 channel
->fOutputEnabled
= enabled
;
1141 MultiAudioNode::AdditionalBufferRequested(const media_source
& source
,
1142 media_buffer_id previousBuffer
, bigtime_t previousTime
,
1143 const media_seek_tag
* previousTag
)
1146 // we don't support offline mode
1151 // #pragma mark - BMediaEventLooper
1155 MultiAudioNode::HandleEvent(const media_timed_event
* event
, bigtime_t lateness
,
1158 switch (event
->type
) {
1159 case BTimedEventQueue::B_START
:
1160 _HandleStart(event
, lateness
, realTimeEvent
);
1162 case BTimedEventQueue::B_SEEK
:
1163 _HandleSeek(event
, lateness
, realTimeEvent
);
1165 case BTimedEventQueue::B_WARP
:
1166 _HandleWarp(event
, lateness
, realTimeEvent
);
1168 case BTimedEventQueue::B_STOP
:
1169 _HandleStop(event
, lateness
, realTimeEvent
);
1171 case BTimedEventQueue::B_HANDLE_BUFFER
:
1172 if (RunState() == BMediaEventLooper::B_STARTED
)
1173 _HandleBuffer(event
, lateness
, realTimeEvent
);
1175 case BTimedEventQueue::B_DATA_STATUS
:
1176 _HandleDataStatus(event
, lateness
, realTimeEvent
);
1178 case BTimedEventQueue::B_PARAMETER
:
1179 _HandleParameter(event
, lateness
, realTimeEvent
);
1182 fprintf(stderr
," unknown event type: %" B_PRId32
"\n",
1190 MultiAudioNode::_HandleBuffer(const media_timed_event
* event
,
1191 bigtime_t lateness
, bool realTimeEvent
)
1193 BBuffer
* buffer
= const_cast<BBuffer
*>((BBuffer
*)event
->pointer
);
1197 //PRINT(("buffer->Header()->destination: %i\n", buffer->Header()->destination));
1199 node_input
* channel
= _FindInput(buffer
->Header()->destination
);
1200 if (channel
== NULL
) {
1202 return B_MEDIA_BAD_DESTINATION
;
1205 // if the buffer is late, we ignore it and report the fact to the producer
1206 // who sent it to us
1207 if (RunMode() != B_OFFLINE
&& RunMode() != B_RECORDING
&& lateness
> 0) {
1208 // lateness doesn't matter in offline mode or in recording mode
1210 NotifyLateProducer(channel
->fInput
.source
, lateness
, event
->event_time
);
1211 fprintf(stderr
," <- LATE BUFFER: %" B_PRIdBIGTIME
"\n", lateness
);
1214 //WriteBuffer(buffer, *channel);
1215 // TODO: This seems like a very fragile mechanism to wait until
1216 // the previous buffer for this channel has been processed...
1217 if (channel
->fBuffer
!= NULL
) {
1218 PRINT(("MultiAudioNode::HandleBuffer snoozing recycling channelId: "
1219 "%" B_PRIi32
", how_early:%" B_PRIdBIGTIME
"\n",
1220 channel
->fChannelId
, lateness
));
1221 //channel->fBuffer->Recycle();
1223 if (channel
->fBuffer
!= NULL
)
1226 channel
->fBuffer
= buffer
;
1228 //PRINT(("MultiAudioNode::HandleBuffer writing channelId: %li, how_early:%Ld\n", channel->fChannelId, howEarly));
1229 channel
->fBuffer
= buffer
;
1237 MultiAudioNode::_HandleDataStatus(const media_timed_event
* event
,
1238 bigtime_t lateness
, bool realTimeEvent
)
1240 PRINT(("MultiAudioNode::HandleDataStatus status:%" B_PRIi32
", lateness:%"
1241 B_PRIiBIGTIME
"\n", event
->data
, lateness
));
1242 switch (event
->data
) {
1243 case B_DATA_NOT_AVAILABLE
:
1245 case B_DATA_AVAILABLE
:
1247 case B_PRODUCER_STOPPED
:
1257 MultiAudioNode::_HandleStart(const media_timed_event
* event
, bigtime_t lateness
,
1261 if (RunState() != B_STARTED
) {
1268 MultiAudioNode::_HandleSeek(const media_timed_event
* event
, bigtime_t lateness
,
1272 PRINT(("MultiAudioNode::HandleSeek(t=%" B_PRIdBIGTIME
",d=%" B_PRIi32
1273 ",bd=%" B_PRId64
")\n",
1274 event
->event_time
,event
->data
,event
->bigdata
));
1280 MultiAudioNode::_HandleWarp(const media_timed_event
* event
, bigtime_t lateness
,
1289 MultiAudioNode::_HandleStop(const media_timed_event
* event
, bigtime_t lateness
,
1293 // flush the queue so downstreamers don't get any more
1294 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS
, true,
1295 BTimedEventQueue::B_HANDLE_BUFFER
);
1297 //_StopOutputThread();
1303 MultiAudioNode::_HandleParameter(const media_timed_event
* event
,
1304 bigtime_t lateness
, bool realTimeEvent
)
1311 // #pragma mark - BTimeSource
1315 MultiAudioNode::SetRunMode(run_mode mode
)
1318 PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode
));
1319 //BTimeSource::SetRunMode(mode);
1324 MultiAudioNode::TimeSourceOp(const time_source_op_info
& op
, void* _reserved
)
1328 case B_TIMESOURCE_START
:
1329 PRINT(("TimeSourceOp op B_TIMESOURCE_START\n"));
1330 if (RunState() != BMediaEventLooper::B_STARTED
) {
1331 fTimeSourceStarted
= true;
1332 _StartOutputThreadIfNeeded();
1334 media_timed_event
startEvent(0, BTimedEventQueue::B_START
);
1335 EventQueue()->AddEvent(startEvent
);
1338 case B_TIMESOURCE_STOP
:
1339 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP\n"));
1340 if (RunState() == BMediaEventLooper::B_STARTED
) {
1341 media_timed_event
stopEvent(0, BTimedEventQueue::B_STOP
);
1342 EventQueue()->AddEvent(stopEvent
);
1343 fTimeSourceStarted
= false;
1344 _StopOutputThread();
1345 PublishTime(0, 0, 0);
1348 case B_TIMESOURCE_STOP_IMMEDIATELY
:
1349 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP_IMMEDIATELY\n"));
1350 if (RunState() == BMediaEventLooper::B_STARTED
) {
1351 media_timed_event
stopEvent(0, BTimedEventQueue::B_STOP
);
1352 EventQueue()->AddEvent(stopEvent
);
1353 fTimeSourceStarted
= false;
1354 _StopOutputThread();
1355 PublishTime(0, 0, 0);
1358 case B_TIMESOURCE_SEEK
:
1359 PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n"));
1360 BroadcastTimeWarp(op
.real_time
, op
.performance_time
);
1369 // #pragma mark - BControllable
1373 MultiAudioNode::GetParameterValue(int32 id
, bigtime_t
* lastChange
, void* value
,
1378 PRINT(("id: %" B_PRIi32
"\n", id
));
1379 BParameter
* parameter
= NULL
;
1380 for (int32 i
= 0; i
< fWeb
->CountParameters(); i
++) {
1381 parameter
= fWeb
->ParameterAt(i
);
1382 if (parameter
->ID() == id
)
1386 if (parameter
== NULL
) {
1387 // Hmmm, we were asked for a parameter that we don't actually
1388 // support. Report an error back to the caller.
1389 PRINT(("\terror - asked for illegal parameter %" B_PRId32
"\n", id
));
1393 if (id
== PARAMETER_ID_INPUT_FREQUENCY
1394 || id
== PARAMETER_ID_OUTPUT_FREQUENCY
) {
1395 const multi_format_info
& info
= fDevice
->FormatInfo();
1397 uint32 rate
= id
== PARAMETER_ID_INPUT_FREQUENCY
1398 ? info
.input
.rate
: info
.output
.rate
;
1400 if (*size
< sizeof(rate
))
1403 memcpy(value
, &rate
, sizeof(rate
));
1404 *size
= sizeof(rate
);
1408 multi_mix_value_info info
;
1409 multi_mix_value values
[2];
1410 info
.values
= values
;
1411 info
.item_count
= 0;
1412 multi_mix_control
* controls
= fDevice
->MixControlInfo().controls
;
1413 int32 control_id
= controls
[id
- 100].id
;
1415 if (*size
< sizeof(float))
1418 if (parameter
->Type() == BParameter::B_CONTINUOUS_PARAMETER
) {
1419 info
.item_count
= 1;
1420 values
[0].id
= control_id
;
1422 if (parameter
->CountChannels() == 2) {
1423 if (*size
< 2*sizeof(float))
1425 info
.item_count
= 2;
1426 values
[1].id
= controls
[id
+ 1 - 100].id
;
1428 } else if (parameter
->Type() == BParameter::B_DISCRETE_PARAMETER
) {
1429 info
.item_count
= 1;
1430 values
[0].id
= control_id
;
1433 if (info
.item_count
> 0) {
1434 status_t status
= fDevice
->GetMix(&info
);
1435 if (status
!= B_OK
) {
1436 fprintf(stderr
, "Failed on DRIVER_GET_MIX\n");
1438 if (parameter
->Type() == BParameter::B_CONTINUOUS_PARAMETER
) {
1439 ((float*)value
)[0] = values
[0].gain
;
1440 *size
= sizeof(float);
1442 if (parameter
->CountChannels() == 2) {
1443 ((float*)value
)[1] = values
[1].gain
;
1444 *size
= 2*sizeof(float);
1447 for (uint32 i
= 0; i
< *size
/ sizeof(float); i
++) {
1448 PRINT(("GetParameterValue B_CONTINUOUS_PARAMETER value[%"
1449 B_PRIi32
"]: %f\n", i
, ((float*)value
)[i
]));
1451 } else if (parameter
->Type() == BParameter::B_DISCRETE_PARAMETER
) {
1452 BDiscreteParameter
* discrete
= (BDiscreteParameter
*)parameter
;
1453 if (discrete
->CountItems() <= 2)
1454 ((int32
*)value
)[0] = values
[0].enable
? 1 : 0;
1456 ((int32
*)value
)[0] = values
[0].mux
;
1458 *size
= sizeof(int32
);
1460 for (uint32 i
= 0; i
< *size
/ sizeof(int32
); i
++) {
1461 PRINT(("GetParameterValue B_DISCRETE_PARAMETER value[%"
1462 B_PRIi32
"]: %" B_PRIi32
"\n", i
, ((int32
*)value
)[i
]));
1472 MultiAudioNode::SetParameterValue(int32 id
, bigtime_t performanceTime
,
1473 const void* value
, size_t size
)
1476 PRINT(("id: %" B_PRIi32
", performance_time: %" B_PRIdBIGTIME
1477 ", size: %" B_PRIuSIZE
"\n", id
, performanceTime
, size
));
1479 BParameter
* parameter
= NULL
;
1480 for (int32 i
= 0; i
< fWeb
->CountParameters(); i
++) {
1481 parameter
= fWeb
->ParameterAt(i
);
1482 if (parameter
->ID() == id
)
1486 if (parameter
== NULL
)
1489 if (id
== PARAMETER_ID_OUTPUT_FREQUENCY
1490 || (id
== PARAMETER_ID_INPUT_FREQUENCY
1491 && (fDevice
->Description().output_rates
1492 & B_SR_SAME_AS_INPUT
) != 0)) {
1494 if (size
< sizeof(rate
))
1496 memcpy(&rate
, value
, sizeof(rate
));
1498 if (rate
== fOutputPreferredFormat
.u
.raw_audio
.frame_rate
)
1501 // create a cookie RequestCompleted() can get the old frame rate from,
1502 // if anything goes wrong
1503 FrameRateChangeCookie
* cookie
= new(std::nothrow
) FrameRateChangeCookie
;
1507 cookie
->oldFrameRate
= fOutputPreferredFormat
.u
.raw_audio
.frame_rate
;
1509 BReference
<FrameRateChangeCookie
> cookieReference(cookie
, true);
1511 // NOTE: What we should do is call RequestFormatChange() for all
1512 // connections and change the device's format in RequestCompleted().
1513 // Unfortunately we need the new buffer size first, which we only get
1514 // from the device after changing the format. So we do that now and
1515 // reset it in RequestCompleted(), if something went wrong. This causes
1516 // the buffers we receive until then to be played incorrectly leading
1517 // to unpleasant noise.
1518 float frameRate
= MultiAudio::convert_to_sample_rate(rate
);
1519 if (_SetNodeInputFrameRate(frameRate
) != B_OK
)
1522 for (int32 i
= 0; i
< fInputs
.CountItems(); i
++) {
1523 node_input
* channel
= (node_input
*)fInputs
.ItemAt(i
);
1524 if (channel
->fInput
.source
== media_source::null
)
1527 media_format newFormat
= channel
->fInput
.format
;
1528 newFormat
.u
.raw_audio
.frame_rate
= frameRate
;
1529 newFormat
.u
.raw_audio
.buffer_size
1530 = fOutputPreferredFormat
.u
.raw_audio
.buffer_size
;
1532 int32 changeTag
= 0;
1533 status_t error
= RequestFormatChange(channel
->fInput
.source
,
1534 channel
->fInput
.destination
, newFormat
, NULL
, &changeTag
);
1536 cookie
->AcquireReference();
1539 if (id
!= PARAMETER_ID_INPUT_FREQUENCY
)
1541 //Do not return cause we should go in the next if
1544 if (id
== PARAMETER_ID_INPUT_FREQUENCY
) {
1546 if (size
< sizeof(rate
))
1548 memcpy(&rate
, value
, sizeof(rate
));
1550 if (rate
== fInputPreferredFormat
.u
.raw_audio
.frame_rate
)
1553 // create a cookie RequestCompleted() can get the old frame rate from,
1554 // if anything goes wrong
1555 FrameRateChangeCookie
* cookie
= new(std::nothrow
) FrameRateChangeCookie
;
1559 cookie
->oldFrameRate
= fInputPreferredFormat
.u
.raw_audio
.frame_rate
;
1561 BReference
<FrameRateChangeCookie
> cookieReference(cookie
, true);
1563 // NOTE: What we should do is call RequestFormatChange() for all
1564 // connections and change the device's format in RequestCompleted().
1565 // Unfortunately we need the new buffer size first, which we only get
1566 // from the device after changing the format. So we do that now and
1567 // reset it in RequestCompleted(), if something went wrong. This causes
1568 // the buffers we receive until then to be played incorrectly leading
1569 // to unpleasant noise.
1570 float frameRate
= MultiAudio::convert_to_sample_rate(rate
);
1571 if (_SetNodeOutputFrameRate(frameRate
) != B_OK
)
1574 for (int32 i
= 0; i
< fOutputs
.CountItems(); i
++) {
1575 node_output
* channel
= (node_output
*)fOutputs
.ItemAt(i
);
1576 if (channel
->fOutput
.source
== media_source::null
)
1579 media_format newFormat
= channel
->fOutput
.format
;
1580 newFormat
.u
.raw_audio
.frame_rate
= frameRate
;
1581 newFormat
.u
.raw_audio
.buffer_size
1582 = fInputPreferredFormat
.u
.raw_audio
.buffer_size
;
1584 int32 changeTag
= 0;
1585 status_t error
= RequestFormatChange(channel
->fOutput
.source
,
1586 channel
->fOutput
.destination
, newFormat
, NULL
, &changeTag
);
1588 cookie
->AcquireReference();
1594 multi_mix_value_info info
;
1595 multi_mix_value values
[2];
1596 info
.values
= values
;
1597 info
.item_count
= 0;
1598 multi_mix_control
* controls
= fDevice
->MixControlInfo().controls
;
1599 int32 control_id
= controls
[id
- 100].id
;
1601 if (parameter
->Type() == BParameter::B_CONTINUOUS_PARAMETER
) {
1602 for (uint32 i
= 0; i
< size
/ sizeof(float); i
++) {
1603 PRINT(("SetParameterValue B_CONTINUOUS_PARAMETER value[%" B_PRIi32
1604 "]: %f\n", i
, ((float*)value
)[i
]));
1606 info
.item_count
= 1;
1607 values
[0].id
= control_id
;
1608 values
[0].gain
= ((float*)value
)[0];
1610 if (parameter
->CountChannels() == 2) {
1611 info
.item_count
= 2;
1612 values
[1].id
= controls
[id
+ 1 - 100].id
;
1613 values
[1].gain
= ((float*)value
)[1];
1615 } else if (parameter
->Type() == BParameter::B_DISCRETE_PARAMETER
) {
1616 for (uint32 i
= 0; i
< size
/ sizeof(int32
); i
++) {
1617 PRINT(("SetParameterValue B_DISCRETE_PARAMETER value[%" B_PRIi32
1618 "]: %" B_PRIi32
"\n", i
, ((int32
*)value
)[i
]));
1621 BDiscreteParameter
* discrete
= (BDiscreteParameter
*)parameter
;
1622 if (discrete
->CountItems() <= 2) {
1623 info
.item_count
= 1;
1624 values
[0].id
= control_id
;
1625 values
[0].enable
= ((int32
*)value
)[0] == 1;
1627 info
.item_count
= 1;
1628 values
[0].id
= control_id
;
1629 values
[0].mux
= ((uint32
*)value
)[0];
1633 if (info
.item_count
> 0) {
1634 status_t status
= fDevice
->SetMix(&info
);
1636 fprintf(stderr
, "Failed on DRIVER_SET_MIX\n");
1642 MultiAudioNode::MakeParameterWeb()
1645 BParameterWeb
* web
= new BParameterWeb();
1647 PRINT(("MixControlInfo().control_count: %" B_PRIi32
"\n",
1648 fDevice
->MixControlInfo().control_count
));
1650 BParameterGroup
* generalGroup
= web
->MakeGroup(B_TRANSLATE("General"));
1652 const multi_description
& description
= fDevice
->Description();
1654 if ((description
.output_rates
& B_SR_SAME_AS_INPUT
) != 0) {
1655 _CreateFrequencyParameterGroup(generalGroup
,
1656 B_TRANSLATE("Input & Output"), PARAMETER_ID_INPUT_FREQUENCY
,
1657 description
.input_rates
);
1659 _CreateFrequencyParameterGroup(generalGroup
, B_TRANSLATE("Input"),
1660 PARAMETER_ID_INPUT_FREQUENCY
, description
.input_rates
);
1661 _CreateFrequencyParameterGroup(generalGroup
, B_TRANSLATE("Output"),
1662 PARAMETER_ID_OUTPUT_FREQUENCY
, description
.output_rates
);
1665 multi_mix_control
* controls
= fDevice
->MixControlInfo().controls
;
1667 for (int i
= 0; i
< fDevice
->MixControlInfo().control_count
; i
++) {
1668 if ((controls
[i
].flags
& B_MULTI_MIX_GROUP
) != 0
1669 && controls
[i
].parent
== 0) {
1670 PRINT(("NEW_GROUP\n"));
1671 BParameterGroup
* child
= web
->MakeGroup(
1672 _GetControlName(controls
[i
]));
1674 int32 numParameters
= 0;
1675 _ProcessGroup(child
, i
, numParameters
);
1684 MultiAudioNode::_GetControlName(multi_mix_control
& control
)
1686 if (control
.string
!= S_null
)
1687 return kMultiControlString
[control
.string
];
1689 return control
.name
;
1694 MultiAudioNode::_ProcessGroup(BParameterGroup
* group
, int32 index
,
1695 int32
& numParameters
)
1698 multi_mix_control
* parent
= &fDevice
->MixControlInfo().controls
[index
];
1699 multi_mix_control
* controls
= fDevice
->MixControlInfo().controls
;
1701 for (int32 i
= 0; i
< fDevice
->MixControlInfo().control_count
; i
++) {
1702 if (controls
[i
].parent
!= parent
->id
)
1705 const char* name
= _GetControlName(controls
[i
]);
1707 if (controls
[i
].flags
& B_MULTI_MIX_GROUP
) {
1708 PRINT(("NEW_GROUP\n"));
1709 BParameterGroup
* child
= group
->MakeGroup(name
);
1710 child
->MakeNullParameter(100 + i
, B_MEDIA_RAW_AUDIO
, name
,
1711 B_WEB_BUFFER_OUTPUT
);
1714 _ProcessGroup(child
, i
, num
);
1715 } else if (controls
[i
].flags
& B_MULTI_MIX_MUX
) {
1716 PRINT(("NEW_MUX\n"));
1717 BDiscreteParameter
* parameter
= group
->MakeDiscreteParameter(
1718 100 + i
, B_MEDIA_RAW_AUDIO
, name
, B_INPUT_MUX
);
1719 if (numParameters
> 0) {
1720 (group
->ParameterAt(numParameters
- 1))->AddOutput(
1721 group
->ParameterAt(numParameters
));
1724 _ProcessMux(parameter
, i
);
1725 } else if (controls
[i
].flags
& B_MULTI_MIX_GAIN
) {
1726 PRINT(("NEW_GAIN\n"));
1727 group
->MakeContinuousParameter(100 + i
,
1728 B_MEDIA_RAW_AUDIO
, "", B_MASTER_GAIN
, "dB",
1729 controls
[i
].gain
.min_gain
, controls
[i
].gain
.max_gain
,
1730 controls
[i
].gain
.granularity
);
1732 if (i
+ 1 < fDevice
->MixControlInfo().control_count
1733 && controls
[i
+ 1].master
== controls
[i
].id
1734 && (controls
[i
+ 1].flags
& B_MULTI_MIX_GAIN
) != 0) {
1735 group
->ParameterAt(numParameters
)->SetChannelCount(
1736 group
->ParameterAt(numParameters
)->CountChannels() + 1);
1740 PRINT(("num parameters: %" B_PRId32
"\n", numParameters
));
1741 if (numParameters
> 0) {
1742 group
->ParameterAt(numParameters
- 1)->AddOutput(
1743 group
->ParameterAt(numParameters
));
1746 } else if (controls
[i
].flags
& B_MULTI_MIX_ENABLE
) {
1747 PRINT(("NEW_ENABLE\n"));
1748 if (controls
[i
].string
== S_MUTE
) {
1749 group
->MakeDiscreteParameter(100 + i
,
1750 B_MEDIA_RAW_AUDIO
, name
, B_MUTE
);
1752 group
->MakeDiscreteParameter(100 + i
,
1753 B_MEDIA_RAW_AUDIO
, name
, B_ENABLE
);
1755 if (numParameters
> 0) {
1756 group
->ParameterAt(numParameters
- 1)->AddOutput(
1757 group
->ParameterAt(numParameters
));
1766 MultiAudioNode::_ProcessMux(BDiscreteParameter
* parameter
, int32 index
)
1769 multi_mix_control
* parent
= &fDevice
->MixControlInfo().controls
[index
];
1770 multi_mix_control
* controls
= fDevice
->MixControlInfo().controls
;
1771 int32 itemIndex
= 0;
1773 for (int32 i
= 0; i
< fDevice
->MixControlInfo().control_count
; i
++) {
1774 if (controls
[i
].parent
!= parent
->id
)
1777 if ((controls
[i
].flags
& B_MULTI_MIX_MUX_VALUE
) != 0) {
1778 PRINT(("NEW_MUX_VALUE\n"));
1779 parameter
->AddItem(itemIndex
, _GetControlName(controls
[i
]));
1787 MultiAudioNode::_CreateFrequencyParameterGroup(BParameterGroup
* parentGroup
,
1788 const char* name
, int32 parameterID
, uint32 rateMask
)
1790 BParameterGroup
* group
= parentGroup
->MakeGroup(name
);
1791 BDiscreteParameter
* frequencyParam
= group
->MakeDiscreteParameter(
1792 parameterID
, B_MEDIA_NO_TYPE
,
1793 BString(name
) << B_TRANSLATE(" frequency:"),
1796 for (int32 i
= 0; kSampleRateInfos
[i
].name
!= NULL
; i
++) {
1797 const sample_rate_info
& info
= kSampleRateInfos
[i
];
1798 if ((rateMask
& info
.multiAudioRate
) != 0) {
1799 frequencyParam
->AddItem(info
.multiAudioRate
,
1800 BString(info
.name
) << " Hz");
1806 // #pragma mark - MultiAudioNode specific functions
1810 MultiAudioNode::_OutputThread()
1813 multi_buffer_info bufferInfo
;
1814 bufferInfo
.info_size
= sizeof(multi_buffer_info
);
1815 bufferInfo
.playback_buffer_cycle
= 0;
1816 bufferInfo
.record_buffer_cycle
= 0;
1818 // init the performance time computation
1820 BAutolock
locker(fBufferLock
);
1821 fTimeComputer
.Init(fOutputPreferredFormat
.u
.raw_audio
.frame_rate
,
1825 while (atomic_get(&fQuitThread
) == 0) {
1826 BAutolock
locker(fBufferLock
);
1827 // make sure the buffers don't change while we're playing with them
1830 fDevice
->BufferExchange(&bufferInfo
);
1832 //PRINT(("MultiAudioNode::RunThread: buffer exchanged\n"));
1833 //PRINT(("MultiAudioNode::RunThread: played_real_time: %Ld\n", bufferInfo.played_real_time));
1834 //PRINT(("MultiAudioNode::RunThread: played_frames_count: %Ld\n", bufferInfo.played_frames_count));
1835 //PRINT(("MultiAudioNode::RunThread: buffer_cycle: %li\n", bufferInfo.playback_buffer_cycle));
1837 for (int32 i
= 0; i
< fInputs
.CountItems(); i
++) {
1838 node_input
* input
= (node_input
*)fInputs
.ItemAt(i
);
1840 if (bufferInfo
.playback_buffer_cycle
>= 0
1841 && bufferInfo
.playback_buffer_cycle
1842 < fDevice
->BufferList().return_playback_buffers
1843 && (input
->fOldBufferInfo
.playback_buffer_cycle
1844 != bufferInfo
.playback_buffer_cycle
1845 || fDevice
->BufferList().return_playback_buffers
== 1)
1846 && (input
->fInput
.source
!= media_source::null
1847 || input
->fChannelId
== 0)) {
1848 //PRINT(("playback_buffer_cycle ok input: %li %ld\n", i, bufferInfo.playback_buffer_cycle));
1850 input
->fBufferCycle
= (bufferInfo
.playback_buffer_cycle
- 1
1851 + fDevice
->BufferList().return_playback_buffers
)
1852 % fDevice
->BufferList().return_playback_buffers
;
1854 // update the timesource
1855 if (input
->fChannelId
== 0) {
1856 //PRINT(("updating timesource\n"));
1857 _UpdateTimeSource(bufferInfo
, input
->fOldBufferInfo
,
1861 input
->fOldBufferInfo
= bufferInfo
;
1863 if (input
->fBuffer
!= NULL
) {
1864 _FillNextBuffer(*input
, input
->fBuffer
);
1865 input
->fBuffer
->Recycle();
1866 input
->fBuffer
= NULL
;
1868 // put zeros in current buffer
1869 if (input
->fInput
.source
!= media_source::null
)
1870 _WriteZeros(*input
, input
->fBufferCycle
);
1871 //PRINT(("MultiAudioNode::Runthread WriteZeros\n"));
1874 //PRINT(("playback_buffer_cycle non ok input: %i\n", i));
1878 PRINT(("MultiAudioNode::RunThread: recorded_real_time: %" B_PRIdBIGTIME
1879 "\n", bufferInfo
.recorded_real_time
));
1880 PRINT(("MultiAudioNode::RunThread: recorded_frames_count: %"
1881 B_PRId64
"\n", bufferInfo
.recorded_frames_count
));
1882 PRINT(("MultiAudioNode::RunThread: record_buffer_cycle: %" B_PRIi32
1883 "\n", bufferInfo
.record_buffer_cycle
));
1885 for (int32 i
= 0; i
< fOutputs
.CountItems(); i
++) {
1886 node_output
* output
= (node_output
*)fOutputs
.ItemAt(i
);
1888 // make sure we're both started *and* connected before delivering a
1890 if (RunState() == BMediaEventLooper::B_STARTED
1891 && output
->fOutput
.destination
!= media_destination::null
) {
1892 if (bufferInfo
.record_buffer_cycle
>= 0
1893 && bufferInfo
.record_buffer_cycle
1894 < fDevice
->BufferList().return_record_buffers
1895 && (output
->fOldBufferInfo
.record_buffer_cycle
1896 != bufferInfo
.record_buffer_cycle
1897 || fDevice
->BufferList().return_record_buffers
== 1)) {
1898 //PRINT(("record_buffer_cycle ok\n"));
1900 output
->fBufferCycle
= bufferInfo
.record_buffer_cycle
;
1902 // Get the next buffer of data
1903 BBuffer
* buffer
= _FillNextBuffer(bufferInfo
, *output
);
1904 if (buffer
!= NULL
) {
1905 // send the buffer downstream if and only if output is
1907 status_t err
= B_ERROR
;
1908 if (output
->fOutputEnabled
) {
1909 err
= SendBuffer(buffer
, output
->fOutput
.source
,
1910 output
->fOutput
.destination
);
1915 // track how much media we've delivered so far
1917 = output
->fOutput
.format
.u
.raw_audio
.buffer_size
1918 / (output
->fOutput
.format
.u
.raw_audio
.format
1919 & media_raw_audio_format
1920 ::B_AUDIO_SIZE_MASK
);
1921 output
->fSamplesSent
+= numSamples
;
1925 output
->fOldBufferInfo
= bufferInfo
;
1927 //PRINT(("record_buffer_cycle non ok\n"));
1938 MultiAudioNode::_WriteZeros(node_input
& input
, uint32 bufferCycle
)
1941 /*int32 samples = input.fInput.format.u.raw_audio.buffer_size;
1942 if(input.fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_UCHAR) {
1943 uint8 *sample = (uint8*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base;
1944 for(int32 i = samples-1; i>=0; i--)
1947 int32 *sample = (int32*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base;
1948 for(int32 i = (samples / 4)-1; i>=0; i--)
1952 uint32 channelCount
= input
.fFormat
.u
.raw_audio
.channel_count
;
1953 uint32 bufferSize
= fDevice
->BufferList().return_playback_buffer_size
;
1954 size_t stride
= fDevice
->BufferList().playback_buffers
[bufferCycle
]
1955 [input
.fChannelId
].stride
;
1957 switch (input
.fFormat
.u
.raw_audio
.format
) {
1958 case media_raw_audio_format::B_AUDIO_FLOAT
:
1959 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
1960 char* dest
= _PlaybackBuffer(bufferCycle
,
1961 input
.fChannelId
+ channel
);
1962 for (uint32 i
= bufferSize
; i
> 0; i
--) {
1969 case media_raw_audio_format::B_AUDIO_DOUBLE
:
1970 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
1971 char* dest
= _PlaybackBuffer(bufferCycle
,
1972 input
.fChannelId
+ channel
);
1973 for (uint32 i
= bufferSize
; i
> 0; i
--) {
1980 case media_raw_audio_format::B_AUDIO_INT
:
1981 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
1982 char* dest
= _PlaybackBuffer(bufferCycle
,
1983 input
.fChannelId
+ channel
);
1984 for (uint32 i
= bufferSize
; i
> 0; i
--) {
1991 case media_raw_audio_format::B_AUDIO_SHORT
:
1992 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
1993 char* dest
= _PlaybackBuffer(bufferCycle
,
1994 input
.fChannelId
+ channel
);
1995 for (uint32 i
= bufferSize
; i
> 0; i
--) {
2002 case media_raw_audio_format::B_AUDIO_UCHAR
:
2003 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
2004 char* dest
= _PlaybackBuffer(bufferCycle
,
2005 input
.fChannelId
+ channel
);
2006 for (uint32 i
= bufferSize
; i
> 0; i
--) {
2007 *(uint8
*)dest
= 128;
2013 case media_raw_audio_format::B_AUDIO_CHAR
:
2014 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
2015 char* dest
= _PlaybackBuffer(bufferCycle
,
2016 input
.fChannelId
+ channel
);
2017 for (uint32 i
= bufferSize
; i
> 0; i
--) {
2025 fprintf(stderr
, "ERROR in WriteZeros format not handled\n");
2031 MultiAudioNode::_FillWithZeros(node_input
& input
)
2034 for (int32 i
= 0; i
< fDevice
->BufferList().return_playback_buffers
; i
++)
2035 _WriteZeros(input
, i
);
2040 MultiAudioNode::_FillNextBuffer(node_input
& input
, BBuffer
* buffer
)
2042 uint32 channelCount
= input
.fInput
.format
.u
.raw_audio
.channel_count
;
2043 size_t inputSampleSize
= input
.fInput
.format
.u
.raw_audio
.format
2044 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
2046 uint32 bufferSize
= fDevice
->BufferList().return_playback_buffer_size
;
2048 if (buffer
->SizeUsed() / inputSampleSize
/ channelCount
!= bufferSize
) {
2049 _WriteZeros(input
, input
.fBufferCycle
);
2053 if (channelCount
!= input
.fFormat
.u
.raw_audio
.channel_count
) {
2054 PRINT(("Channel count is different"));
2058 if (input
.fResampler
!= NULL
) {
2059 size_t srcStride
= channelCount
* inputSampleSize
;
2061 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
2062 char* src
= (char*)buffer
->Data() + channel
* inputSampleSize
;
2063 char* dst
= _PlaybackBuffer(input
.fBufferCycle
,
2064 input
.fChannelId
+ channel
);
2065 size_t dstStride
= _PlaybackStride(input
.fBufferCycle
,
2066 input
.fChannelId
+ channel
);
2068 input
.fResampler
->Resample(src
, srcStride
,
2069 dst
, dstStride
, bufferSize
);
2076 MultiAudioNode::_StartOutputThreadIfNeeded()
2079 // the thread is already started ?
2083 PublishTime(-50, 0, 0);
2085 fThread
= spawn_thread(_OutputThreadEntry
, "multi_audio audio output",
2086 B_REAL_TIME_PRIORITY
, this);
2090 resume_thread(fThread
);
2096 MultiAudioNode::_StopOutputThread()
2099 atomic_set(&fQuitThread
, 1);
2101 wait_for_thread(fThread
, NULL
);
2108 MultiAudioNode::_AllocateBuffers(node_output
&channel
)
2112 // allocate enough buffers to span our downstream latency, plus one
2113 size_t size
= channel
.fOutput
.format
.u
.raw_audio
.buffer_size
;
2114 int32 count
= int32(fLatency
/ BufferDuration() + 1 + 1);
2116 PRINT(("\tlatency = %" B_PRIdBIGTIME
", buffer duration = %" B_PRIdBIGTIME
2117 "\n", fLatency
, BufferDuration()));
2118 PRINT(("\tcreating group of %" B_PRId32
" buffers, size = %" B_PRIuSIZE
2119 "\n", count
, size
));
2120 channel
.fBufferGroup
= new BBufferGroup(size
, count
);
2125 MultiAudioNode::_UpdateTimeSource(multi_buffer_info
& info
,
2126 multi_buffer_info
& oldInfo
, node_input
& input
)
2129 if (!fTimeSourceStarted
|| oldInfo
.played_real_time
== 0)
2132 fTimeComputer
.AddTimeStamp(info
.played_real_time
,
2133 info
.played_frames_count
);
2134 PublishTime(fTimeComputer
.PerformanceTime(), fTimeComputer
.RealTime(),
2135 fTimeComputer
.Drift());
2140 MultiAudioNode::_FillNextBuffer(multi_buffer_info
& info
, node_output
& output
)
2143 // get a buffer from our buffer group
2144 //PRINT(("buffer size: %i, buffer duration: %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration()));
2145 //PRINT(("MBI.record_buffer_cycle: %i\n", MBI.record_buffer_cycle));
2146 //PRINT(("MBI.recorded_real_time: %i\n", MBI.recorded_real_time));
2147 //PRINT(("MBI.recorded_frames_count: %i\n", MBI.recorded_frames_count));
2148 if (output
.fBufferGroup
== NULL
)
2151 BBuffer
* buffer
= output
.fBufferGroup
->RequestBuffer(
2152 output
.fOutput
.format
.u
.raw_audio
.buffer_size
, BufferDuration());
2153 if (buffer
== NULL
) {
2154 // If we fail to get a buffer (for example, if the request times out),
2155 // we skip this buffer and go on to the next, to avoid locking up the
2157 fprintf(stderr
, "Buffer is null");
2161 if (fDevice
== NULL
)
2162 fprintf(stderr
, "fDevice NULL\n");
2163 if (buffer
->Header() == NULL
)
2164 fprintf(stderr
, "buffer->Header() NULL\n");
2165 if (TimeSource() == NULL
)
2166 fprintf(stderr
, "TimeSource() NULL\n");
2168 uint32 channelCount
= output
.fOutput
.format
.u
.raw_audio
.channel_count
;
2169 size_t outputSampleSize
= output
.fOutput
.format
.u
.raw_audio
.format
2170 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
2172 uint32 bufferSize
= fDevice
->BufferList().return_record_buffer_size
;
2174 if (output
.fResampler
!= NULL
) {
2175 size_t dstStride
= channelCount
* outputSampleSize
;
2177 uint32 channelId
= output
.fChannelId
2178 - fDevice
->Description().output_channel_count
;
2180 for (uint32 channel
= 0; channel
< channelCount
; channel
++) {
2181 char* src
= _RecordBuffer(output
.fBufferCycle
,
2182 channelId
+ channel
);
2183 size_t srcStride
= _RecordStride(output
.fBufferCycle
,
2184 channelId
+ channel
);
2185 char* dst
= (char*)buffer
->Data() + channel
* outputSampleSize
;
2187 output
.fResampler
->Resample(src
, srcStride
, dst
, dstStride
,
2192 // fill in the buffer header
2193 media_header
* header
= buffer
->Header();
2194 header
->type
= B_MEDIA_RAW_AUDIO
;
2195 header
->size_used
= output
.fOutput
.format
.u
.raw_audio
.buffer_size
;
2196 header
->time_source
= TimeSource()->ID();
2197 header
->start_time
= PerformanceTimeFor(info
.recorded_real_time
);
2204 MultiAudioNode::GetConfigurationFor(BMessage
* message
)
2207 if (message
== NULL
)
2210 size_t bufferSize
= 128;
2211 void* buffer
= malloc(bufferSize
);
2215 for (int32 i
= 0; i
< fWeb
->CountParameters(); i
++) {
2216 BParameter
* parameter
= fWeb
->ParameterAt(i
);
2217 if (parameter
->Type() != BParameter::B_CONTINUOUS_PARAMETER
2218 && parameter
->Type() != BParameter::B_DISCRETE_PARAMETER
)
2221 PRINT(("getting parameter %" B_PRIi32
"\n", parameter
->ID()));
2222 size_t size
= bufferSize
;
2223 bigtime_t lastChange
;
2225 while ((err
= GetParameterValue(parameter
->ID(), &lastChange
, buffer
,
2226 &size
)) == B_NO_MEMORY
&& bufferSize
< 128 * 1024) {
2229 buffer
= malloc(bufferSize
);
2234 if (err
== B_OK
&& size
> 0) {
2235 message
->AddInt32("parameterID", parameter
->ID());
2236 message
->AddData("parameterData", B_RAW_TYPE
, buffer
, size
, false);
2238 PRINT(("parameter err: %s\n", strerror(err
)));
2243 PRINT_OBJECT(*message
);
2249 MultiAudioNode::_FindOutput(media_source source
)
2251 node_output
* channel
= NULL
;
2253 for (int32 i
= 0; i
< fOutputs
.CountItems(); i
++) {
2254 channel
= (node_output
*)fOutputs
.ItemAt(i
);
2255 if (source
== channel
->fOutput
.source
)
2259 if (source
!= channel
->fOutput
.source
)
2267 MultiAudioNode::_FindInput(media_destination dest
)
2269 node_input
* channel
= NULL
;
2271 for (int32 i
= 0; i
< fInputs
.CountItems(); i
++) {
2272 channel
= (node_input
*)fInputs
.ItemAt(i
);
2273 if (dest
== channel
->fInput
.destination
)
2277 if (dest
!= channel
->fInput
.destination
)
2285 MultiAudioNode::_FindInput(int32 destinationId
)
2287 node_input
* channel
= NULL
;
2289 for (int32 i
= 0; i
< fInputs
.CountItems(); i
++) {
2290 channel
= (node_input
*)fInputs
.ItemAt(i
);
2291 if (destinationId
== channel
->fInput
.destination
.id
)
2295 if (destinationId
!= channel
->fInput
.destination
.id
)
2303 MultiAudioNode::_OutputThreadEntry(void* data
)
2306 return static_cast<MultiAudioNode
*>(data
)->_OutputThread();
2311 MultiAudioNode::_SetNodeInputFrameRate(float frameRate
)
2313 // check whether the frame rate is supported
2314 uint32 multiAudioRate
= MultiAudio::convert_from_sample_rate(frameRate
);
2315 if ((fDevice
->Description().output_rates
& multiAudioRate
) == 0)
2318 BAutolock
locker(fBufferLock
);
2321 if (fDevice
->FormatInfo().output
.rate
== multiAudioRate
)
2324 // set the frame rate on the device
2325 status_t error
= fDevice
->SetOutputFrameRate(multiAudioRate
);
2329 // it went fine -- update all formats
2330 fOutputPreferredFormat
.u
.raw_audio
.frame_rate
= frameRate
;
2331 fOutputPreferredFormat
.u
.raw_audio
.buffer_size
2332 = fDevice
->BufferList().return_playback_buffer_size
2333 * (fOutputPreferredFormat
.u
.raw_audio
.format
2334 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
2335 * fOutputPreferredFormat
.u
.raw_audio
.channel_count
;
2337 for (int32 i
= 0; node_input
* channel
= (node_input
*)fInputs
.ItemAt(i
);
2339 channel
->fPreferredFormat
.u
.raw_audio
.frame_rate
= frameRate
;
2340 channel
->fPreferredFormat
.u
.raw_audio
.buffer_size
2341 = fOutputPreferredFormat
.u
.raw_audio
.buffer_size
;
2343 channel
->fFormat
.u
.raw_audio
.frame_rate
= frameRate
;
2344 channel
->fFormat
.u
.raw_audio
.buffer_size
2345 = fOutputPreferredFormat
.u
.raw_audio
.buffer_size
;
2347 channel
->fInput
.format
.u
.raw_audio
.frame_rate
= frameRate
;
2348 channel
->fInput
.format
.u
.raw_audio
.buffer_size
2349 = fOutputPreferredFormat
.u
.raw_audio
.buffer_size
;
2352 // make sure the time base is reset
2353 fTimeComputer
.SetFrameRate(frameRate
);
2355 // update internal latency
2356 _UpdateInternalLatency(fOutputPreferredFormat
);
2363 MultiAudioNode::_SetNodeOutputFrameRate(float frameRate
)
2365 // check whether the frame rate is supported
2366 uint32 multiAudioRate
= MultiAudio::convert_from_sample_rate(frameRate
);
2367 if ((fDevice
->Description().input_rates
& multiAudioRate
) == 0)
2370 BAutolock
locker(fBufferLock
);
2373 if (fDevice
->FormatInfo().input
.rate
== multiAudioRate
)
2376 // set the frame rate on the device
2377 status_t error
= fDevice
->SetInputFrameRate(multiAudioRate
);
2381 // it went fine -- update all formats
2382 fInputPreferredFormat
.u
.raw_audio
.frame_rate
= frameRate
;
2383 fInputPreferredFormat
.u
.raw_audio
.buffer_size
2384 = fDevice
->BufferList().return_record_buffer_size
2385 * (fInputPreferredFormat
.u
.raw_audio
.format
2386 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
2387 * fInputPreferredFormat
.u
.raw_audio
.channel_count
;
2389 for (int32 i
= 0; node_output
* channel
= (node_output
*)fOutputs
.ItemAt(i
);
2391 channel
->fPreferredFormat
.u
.raw_audio
.frame_rate
= frameRate
;
2392 channel
->fPreferredFormat
.u
.raw_audio
.buffer_size
2393 = fInputPreferredFormat
.u
.raw_audio
.buffer_size
;
2395 channel
->fFormat
.u
.raw_audio
.frame_rate
= frameRate
;
2396 channel
->fFormat
.u
.raw_audio
.buffer_size
2397 = fInputPreferredFormat
.u
.raw_audio
.buffer_size
;
2399 channel
->fOutput
.format
.u
.raw_audio
.frame_rate
= frameRate
;
2400 channel
->fOutput
.format
.u
.raw_audio
.buffer_size
2401 = fInputPreferredFormat
.u
.raw_audio
.buffer_size
;
2404 // make sure the time base is reset
2405 fTimeComputer
.SetFrameRate(frameRate
);
2407 // update internal latency
2408 _UpdateInternalLatency(fInputPreferredFormat
);
2415 MultiAudioNode::_UpdateInternalLatency(const media_format
& format
)
2417 // use half a buffer length latency
2418 fInternalLatency
= format
.u
.raw_audio
.buffer_size
* 10000 / 2
2419 / ((format
.u
.raw_audio
.format
2420 & media_raw_audio_format::B_AUDIO_SIZE_MASK
)
2421 * format
.u
.raw_audio
.channel_count
)
2422 / ((int32
)(format
.u
.raw_audio
.frame_rate
/ 100));
2424 PRINT((" internal latency = %" B_PRIdBIGTIME
"\n", fInternalLatency
));
2426 SetEventLatency(fInternalLatency
);