BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / add-ons / media / media-add-ons / multi_audio / MultiAudioNode.cpp
blobd28d9d447f609716f0fef7c9415ce4ba5ebaa883
1 /*
2 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
3 * Distributed under the terms of the MIT License.
4 */
7 //! Media add-on for drivers that use the multi audio interface
10 #include "MultiAudioNode.h"
12 #include <stdio.h>
13 #include <string.h>
15 #include <Autolock.h>
16 #include <Buffer.h>
17 #include <BufferGroup.h>
18 #include <Catalog.h>
19 #include <ParameterWeb.h>
20 #include <String.h>
22 #include <Referenceable.h>
24 #include "MultiAudioUtility.h"
25 #ifdef DEBUG
26 # define PRINTING
27 #endif
28 #include "debug.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
39 class node_input {
40 public:
41 node_input(media_input& input, media_format format);
42 ~node_input();
44 int32 fChannelId;
45 media_input fInput;
46 media_format fPreferredFormat;
47 media_format fFormat;
48 volatile uint32 fBufferCycle;
49 multi_buffer_info fOldBufferInfo;
50 BBuffer* fBuffer;
51 Resampler *fResampler;
55 //This represent an hardware input
56 class node_output {
57 public:
58 node_output(media_output& output, media_format format);
59 ~node_output();
61 int32 fChannelId;
62 media_output fOutput;
63 media_format fPreferredFormat;
64 media_format fFormat;
66 BBufferGroup* fBufferGroup;
67 bool fOutputEnabled;
68 uint64 fSamplesSent;
69 volatile uint32 fBufferCycle;
70 multi_buffer_info fOldBufferInfo;
71 Resampler* fResampler;
75 struct FrameRateChangeCookie : public BReferenceable {
76 float oldFrameRate;
77 uint32 id;
81 struct sample_rate_info {
82 uint32 multiAudioRate;
83 const char* name;
87 static const sample_rate_info kSampleRateInfos[] = {
88 {B_SR_8000, "8000"},
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[] = {
109 "NAME IS ATTACHED",
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")
125 // #pragma mark -
128 node_input::node_input(media_input& input, media_format format)
130 CALLED();
131 fInput = input;
132 fPreferredFormat = format;
133 fBufferCycle = 1;
134 fBuffer = NULL;
135 fResampler = NULL;
139 node_input::~node_input()
141 CALLED();
145 // #pragma mark -
148 node_output::node_output(media_output& output, media_format format)
150 fBufferGroup(NULL),
151 fOutputEnabled(true)
153 CALLED();
154 fOutput = output;
155 fPreferredFormat = format;
156 fBufferCycle = 1;
157 fResampler = NULL;
161 node_output::~node_output()
163 CALLED();
167 // #pragma mark -
170 MultiAudioNode::MultiAudioNode(BMediaAddOn* addon, const char* name,
171 MultiAudioDevice* device, int32 internalID, BMessage* config)
173 BMediaNode(name),
174 BBufferConsumer(B_MEDIA_RAW_AUDIO),
175 BBufferProducer(B_MEDIA_RAW_AUDIO),
176 BMediaEventLooper(),
177 fBufferLock("multi audio buffers"),
178 fQuitThread(0),
179 fThread(-1),
180 fDevice(device),
181 fTimeSourceStarted(false),
182 fWeb(NULL),
183 fConfig()
185 CALLED();
186 fInitStatus = B_NO_INIT;
188 if (!device)
189 return;
191 fAddOn = addon;
192 fId = internalID;
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);
210 // measured in Hertz
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) {
242 fConfig = *config;
243 PRINT_OBJECT(*config);
246 fInitStatus = B_OK;
250 MultiAudioNode::~MultiAudioNode()
252 CALLED();
253 fAddOn->GetConfigurationFor(this, NULL);
255 _StopOutputThread();
256 BMediaEventLooper::Quit();
260 status_t
261 MultiAudioNode::InitCheck() const
263 CALLED();
264 return fInitStatus;
268 void
269 MultiAudioNode::GetFlavor(flavor_info* info, int32 id)
271 CALLED();
272 if (info == NULL)
273 return;
275 info->flavor_flags = 0;
276 info->possible_count = 1;
277 // one flavor at a time
278 info->in_format_count = 0;
279 // no inputs
280 info->in_formats = 0;
281 info->out_format_count = 0;
282 // no outputs
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;
292 // 1 input
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;
298 // 1 output
299 media_format* outFormats = new media_format[info->out_format_count];
300 GetFormat(&outFormats[0]);
301 info->out_formats = outFormats;
305 void
306 MultiAudioNode::GetFormat(media_format* format)
308 CALLED();
309 if (format == NULL)
310 return;
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
322 BMediaAddOn*
323 MultiAudioNode::AddOn(int32* _internalID) const
325 CALLED();
326 // BeBook says this only gets called if we were in an add-on.
327 if (fAddOn != 0 && _internalID != NULL)
328 *_internalID = fId;
330 return fAddOn;
334 void
335 MultiAudioNode::Preroll()
337 CALLED();
338 // TODO: Performance opportunity
339 BMediaNode::Preroll();
343 status_t
344 MultiAudioNode::HandleMessage(int32 message, const void* data, size_t size)
346 CALLED();
347 return B_ERROR;
351 void
352 MultiAudioNode::NodeRegistered()
354 CALLED();
356 if (fInitStatus != B_OK) {
357 ReportError(B_NODE_IN_DISTRESS);
358 return;
361 node_input *currentInput = NULL;
362 int32 currentId = 0;
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",
381 i));
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);
408 currentId = i;
409 } else {
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;
419 currentId = 0;
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",
440 i));
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);
468 currentId = i;
469 } else {
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
481 #ifdef PRINTING
482 bigtime_t start = system_time();
483 #endif
485 int32 index = 0;
486 int32 parameterID = 0;
487 const void *data;
488 ssize_t size;
489 while (fConfig.FindInt32("parameterID", index, &parameterID) == B_OK) {
490 if (fConfig.FindData("parameterData", B_RAW_TYPE, index, &data, &size)
491 == B_OK) {
492 SetParameterValue(parameterID, TimeSource()->Now(), data, size);
494 index++;
497 PRINT(("apply configuration in: %" B_PRIdBIGTIME "\n",
498 system_time() - start));
500 SetPriority(B_REAL_TIME_PRIORITY);
501 Run();
505 status_t
506 MultiAudioNode::RequestCompleted(const media_request_info& info)
508 CALLED();
510 if (info.what != media_request_info::B_REQUEST_FORMAT_CHANGE)
511 return B_OK;
513 FrameRateChangeCookie* cookie
514 = (FrameRateChangeCookie*)info.user_data;
515 if (cookie == NULL)
516 return B_OK;
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
530 // the format back!
533 return B_OK;
537 void
538 MultiAudioNode::SetTimeSource(BTimeSource* timeSource)
540 CALLED();
544 // #pragma mark - BBufferConsumer
547 status_t
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.
553 CALLED();
555 if (format == NULL)
556 return B_BAD_VALUE;
557 if (format->type != B_MEDIA_RAW_AUDIO)
558 return B_MEDIA_BAD_FORMAT;
560 node_input *channel = _FindInput(dest);
561 if (channel == NULL)
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;
579 else*/
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);
602 return B_OK;
606 status_t
607 MultiAudioNode::GetNextInput(int32* cookie, media_input* _input)
609 CALLED();
610 if (_input == NULL)
611 return B_BAD_VALUE;
613 if (*cookie >= fInputs.CountItems() || *cookie < 0)
614 return B_BAD_INDEX;
616 node_input* channel = (node_input*)fInputs.ItemAt(*cookie);
617 *_input = channel->fInput;
618 *cookie += 1;
619 PRINT(("input.format: %" B_PRIu32 "\n",
620 channel->fInput.format.u.raw_audio.format));
621 return B_OK;
625 void
626 MultiAudioNode::DisposeInputCookie(int32 cookie)
628 CALLED();
629 // nothing to do since our cookies are just integers
633 void
634 MultiAudioNode::BufferReceived(BBuffer* buffer)
636 //CALLED();
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");
644 buffer->Recycle();
646 break;*/
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
652 buffer->Recycle();
653 } else {
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");
661 buffer->Recycle();
664 break;
665 default:
666 fprintf(stderr, "unexpected buffer type in "
667 "MultiAudioNode::BufferReceived\n");
668 buffer->Recycle();
669 break;
674 void
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");
682 return;
685 media_timed_event event(atPerformanceTime, BTimedEventQueue::B_DATA_STATUS,
686 &channel->fInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
687 EventQueue()->AddEvent(event);
691 status_t
692 MultiAudioNode::GetLatencyFor(const media_destination& forWhom,
693 bigtime_t* _latency, media_node_id* _timeSource)
695 CALLED();
696 if (_latency == NULL || _timeSource == NULL)
697 return B_BAD_VALUE;
699 node_input* channel = _FindInput(forWhom);
700 if (channel == NULL)
701 return B_MEDIA_BAD_DESTINATION;
703 *_latency = EventLatency();
704 *_timeSource = TimeSource()->ID();
705 return B_OK;
709 status_t
710 MultiAudioNode::Connected(const media_source& producer,
711 const media_destination& where, const media_format& with_format,
712 media_input* out_input)
714 CALLED();
715 if (out_input == 0) {
716 fprintf(stderr, "<- B_BAD_VALUE\n");
717 return B_BAD_VALUE;
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();
735 return B_OK;
739 void
740 MultiAudioNode::Disconnected(const media_source& producer,
741 const media_destination& where)
743 CALLED();
745 node_input* channel = _FindInput(where);
746 if (channel == NULL || channel->fInput.source != producer)
747 return;
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);
758 status_t
759 MultiAudioNode::FormatChanged(const media_source& producer,
760 const media_destination& consumer, int32 change_tag,
761 const media_format& format)
763 CALLED();
765 node_input* channel = _FindInput(consumer);
767 if (channel==NULL) {
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;
774 return B_ERROR;
778 status_t
779 MultiAudioNode::SeekTagRequested(const media_destination& destination,
780 bigtime_t targetTime, uint32 flags, media_seek_tag* _seekTag,
781 bigtime_t* _taggedTime, uint32* _flags)
783 CALLED();
784 return BBufferConsumer::SeekTagRequested(destination, targetTime, flags,
785 _seekTag, _taggedTime, _flags);
789 // #pragma mark - BBufferProducer
792 status_t
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.
800 CALLED();
802 if (format == NULL) {
803 fprintf(stderr, "\tERROR - NULL format pointer passed in!\n");
804 return B_BAD_VALUE;
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;
818 return B_OK;
822 status_t
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.
828 CALLED();
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
840 // acceptable.
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
850 return B_OK;
854 status_t
855 MultiAudioNode::FormatChangeRequested(const media_source& source,
856 const media_destination& destination, media_format* format,
857 int32* _deprecated_)
859 CALLED();
861 // we don't support any other formats, so we just reject any format changes.
862 return B_ERROR;
866 status_t
867 MultiAudioNode::GetNextOutput(int32* cookie, media_output* _output)
869 CALLED();
871 if (*cookie < fOutputs.CountItems() && *cookie >= 0) {
872 node_output* channel = (node_output*)fOutputs.ItemAt(*cookie);
873 *_output = channel->fOutput;
874 *cookie += 1;
875 return B_OK;
877 return B_BAD_INDEX;
881 status_t
882 MultiAudioNode::DisposeOutputCookie(int32 cookie)
884 CALLED();
885 // do nothing because we don't use the cookie for anything special
886 return B_OK;
890 status_t
891 MultiAudioNode::SetBufferGroup(const media_source& forSource,
892 BBufferGroup* newGroup)
894 CALLED();
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)
906 return B_OK;
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;
919 } else {
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) {
926 delete group;
927 fprintf(stderr, "MultiAudioNode::SetBufferGroup failed to"
928 "instantiate a new group.\n");
929 return B_ERROR;
931 channel->fBufferGroup = group;
934 return B_OK;
938 status_t
939 MultiAudioNode::PrepareToConnect(const media_source& what,
940 const media_destination& where, media_format* format,
941 media_source* source, char* name)
943 CALLED();
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);
975 } else {
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);
986 return B_OK;
990 void
991 MultiAudioNode::Connect(status_t error, const media_source& source,
992 const media_destination& destination, const media_format& format,
993 char* name)
995 CALLED();
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");
1002 return;
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;
1011 return;
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.
1031 media_node_id id;
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",
1037 fInternalLatency));
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();
1051 void
1052 MultiAudioNode::Disconnect(const media_source& what,
1053 const media_destination& where)
1055 CALLED();
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");
1062 return;
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;
1072 } else {
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);
1081 void
1082 MultiAudioNode::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
1083 bigtime_t performanceTime)
1085 CALLED();
1087 // is this our output?
1088 node_output* channel = _FindOutput(what);
1089 if (channel == NULL)
1090 return;
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);
1110 } else {
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
1114 // duration.
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");
1123 void
1124 MultiAudioNode::EnableOutput(const media_source& what, bool enabled,
1125 int32* _deprecated_)
1127 CALLED();
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
1133 // accordingly.
1134 node_output* channel = _FindOutput(what);
1135 if (channel != NULL)
1136 channel->fOutputEnabled = enabled;
1140 void
1141 MultiAudioNode::AdditionalBufferRequested(const media_source& source,
1142 media_buffer_id previousBuffer, bigtime_t previousTime,
1143 const media_seek_tag* previousTag)
1145 CALLED();
1146 // we don't support offline mode
1147 return;
1151 // #pragma mark - BMediaEventLooper
1154 void
1155 MultiAudioNode::HandleEvent(const media_timed_event* event, bigtime_t lateness,
1156 bool realTimeEvent)
1158 switch (event->type) {
1159 case BTimedEventQueue::B_START:
1160 _HandleStart(event, lateness, realTimeEvent);
1161 break;
1162 case BTimedEventQueue::B_SEEK:
1163 _HandleSeek(event, lateness, realTimeEvent);
1164 break;
1165 case BTimedEventQueue::B_WARP:
1166 _HandleWarp(event, lateness, realTimeEvent);
1167 break;
1168 case BTimedEventQueue::B_STOP:
1169 _HandleStop(event, lateness, realTimeEvent);
1170 break;
1171 case BTimedEventQueue::B_HANDLE_BUFFER:
1172 if (RunState() == BMediaEventLooper::B_STARTED)
1173 _HandleBuffer(event, lateness, realTimeEvent);
1174 break;
1175 case BTimedEventQueue::B_DATA_STATUS:
1176 _HandleDataStatus(event, lateness, realTimeEvent);
1177 break;
1178 case BTimedEventQueue::B_PARAMETER:
1179 _HandleParameter(event, lateness, realTimeEvent);
1180 break;
1181 default:
1182 fprintf(stderr," unknown event type: %" B_PRId32 "\n",
1183 event->type);
1184 break;
1189 status_t
1190 MultiAudioNode::_HandleBuffer(const media_timed_event* event,
1191 bigtime_t lateness, bool realTimeEvent)
1193 BBuffer* buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
1194 if (buffer == NULL)
1195 return B_BAD_VALUE;
1197 //PRINT(("buffer->Header()->destination: %i\n", buffer->Header()->destination));
1199 node_input* channel = _FindInput(buffer->Header()->destination);
1200 if (channel == NULL) {
1201 buffer->Recycle();
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
1209 //mLateBuffers++;
1210 NotifyLateProducer(channel->fInput.source, lateness, event->event_time);
1211 fprintf(stderr," <- LATE BUFFER: %" B_PRIdBIGTIME "\n", lateness);
1212 buffer->Recycle();
1213 } else {
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();
1222 snooze(100);
1223 if (channel->fBuffer != NULL)
1224 buffer->Recycle();
1225 else
1226 channel->fBuffer = buffer;
1227 } else {
1228 //PRINT(("MultiAudioNode::HandleBuffer writing channelId: %li, how_early:%Ld\n", channel->fChannelId, howEarly));
1229 channel->fBuffer = buffer;
1232 return B_OK;
1236 status_t
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:
1244 break;
1245 case B_DATA_AVAILABLE:
1246 break;
1247 case B_PRODUCER_STOPPED:
1248 break;
1249 default:
1250 break;
1252 return B_OK;
1256 status_t
1257 MultiAudioNode::_HandleStart(const media_timed_event* event, bigtime_t lateness,
1258 bool realTimeEvent)
1260 CALLED();
1261 if (RunState() != B_STARTED) {
1263 return B_OK;
1267 status_t
1268 MultiAudioNode::_HandleSeek(const media_timed_event* event, bigtime_t lateness,
1269 bool realTimeEvent)
1271 CALLED();
1272 PRINT(("MultiAudioNode::HandleSeek(t=%" B_PRIdBIGTIME ",d=%" B_PRIi32
1273 ",bd=%" B_PRId64 ")\n",
1274 event->event_time,event->data,event->bigdata));
1275 return B_OK;
1279 status_t
1280 MultiAudioNode::_HandleWarp(const media_timed_event* event, bigtime_t lateness,
1281 bool realTimeEvent)
1283 CALLED();
1284 return B_OK;
1288 status_t
1289 MultiAudioNode::_HandleStop(const media_timed_event* event, bigtime_t lateness,
1290 bool realTimeEvent)
1292 CALLED();
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();
1298 return B_OK;
1302 status_t
1303 MultiAudioNode::_HandleParameter(const media_timed_event* event,
1304 bigtime_t lateness, bool realTimeEvent)
1306 CALLED();
1307 return B_OK;
1311 // #pragma mark - BTimeSource
1314 void
1315 MultiAudioNode::SetRunMode(run_mode mode)
1317 CALLED();
1318 PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode));
1319 //BTimeSource::SetRunMode(mode);
1323 status_t
1324 MultiAudioNode::TimeSourceOp(const time_source_op_info& op, void* _reserved)
1326 CALLED();
1327 switch (op.op) {
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);
1337 break;
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);
1347 break;
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);
1357 break;
1358 case B_TIMESOURCE_SEEK:
1359 PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n"));
1360 BroadcastTimeWarp(op.real_time, op.performance_time);
1361 break;
1362 default:
1363 break;
1365 return B_OK;
1369 // #pragma mark - BControllable
1372 status_t
1373 MultiAudioNode::GetParameterValue(int32 id, bigtime_t* lastChange, void* value,
1374 size_t* size)
1376 CALLED();
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)
1383 break;
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));
1390 return B_ERROR;
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))
1401 return B_ERROR;
1403 memcpy(value, &rate, sizeof(rate));
1404 *size = sizeof(rate);
1405 return B_OK;
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))
1416 return B_ERROR;
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))
1424 return B_ERROR;
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");
1437 } else {
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;
1455 else
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]));
1467 return B_OK;
1471 void
1472 MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
1473 const void* value, size_t size)
1475 CALLED();
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)
1483 break;
1486 if (parameter == NULL)
1487 return;
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)) {
1493 uint32 rate;
1494 if (size < sizeof(rate))
1495 return;
1496 memcpy(&rate, value, sizeof(rate));
1498 if (rate == fOutputPreferredFormat.u.raw_audio.frame_rate)
1499 return;
1501 // create a cookie RequestCompleted() can get the old frame rate from,
1502 // if anything goes wrong
1503 FrameRateChangeCookie* cookie = new(std::nothrow) FrameRateChangeCookie;
1504 if (cookie == NULL)
1505 return;
1507 cookie->oldFrameRate = fOutputPreferredFormat.u.raw_audio.frame_rate;
1508 cookie->id = id;
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)
1520 return;
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)
1525 continue;
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);
1535 if (error == B_OK)
1536 cookie->AcquireReference();
1539 if (id != PARAMETER_ID_INPUT_FREQUENCY)
1540 return;
1541 //Do not return cause we should go in the next if
1544 if (id == PARAMETER_ID_INPUT_FREQUENCY) {
1545 uint32 rate;
1546 if (size < sizeof(rate))
1547 return;
1548 memcpy(&rate, value, sizeof(rate));
1550 if (rate == fInputPreferredFormat.u.raw_audio.frame_rate)
1551 return;
1553 // create a cookie RequestCompleted() can get the old frame rate from,
1554 // if anything goes wrong
1555 FrameRateChangeCookie* cookie = new(std::nothrow) FrameRateChangeCookie;
1556 if (cookie == NULL)
1557 return;
1559 cookie->oldFrameRate = fInputPreferredFormat.u.raw_audio.frame_rate;
1560 cookie->id = id;
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)
1572 return;
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)
1577 continue;
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);
1587 if (error == B_OK)
1588 cookie->AcquireReference();
1591 return;
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;
1626 } else {
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);
1635 if (status != B_OK)
1636 fprintf(stderr, "Failed on DRIVER_SET_MIX\n");
1641 BParameterWeb*
1642 MultiAudioNode::MakeParameterWeb()
1644 CALLED();
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);
1658 } else {
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);
1679 return web;
1683 const char*
1684 MultiAudioNode::_GetControlName(multi_mix_control& control)
1686 if (control.string != S_null)
1687 return kMultiControlString[control.string];
1689 return control.name;
1693 void
1694 MultiAudioNode::_ProcessGroup(BParameterGroup* group, int32 index,
1695 int32& numParameters)
1697 CALLED();
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)
1703 continue;
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);
1713 int32 num = 1;
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));
1722 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);
1737 i++;
1740 PRINT(("num parameters: %" B_PRId32 "\n", numParameters));
1741 if (numParameters > 0) {
1742 group->ParameterAt(numParameters - 1)->AddOutput(
1743 group->ParameterAt(numParameters));
1744 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);
1751 } else {
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));
1758 numParameters++;
1765 void
1766 MultiAudioNode::_ProcessMux(BDiscreteParameter* parameter, int32 index)
1768 CALLED();
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)
1775 continue;
1777 if ((controls[i].flags & B_MULTI_MIX_MUX_VALUE) != 0) {
1778 PRINT(("NEW_MUX_VALUE\n"));
1779 parameter->AddItem(itemIndex, _GetControlName(controls[i]));
1780 itemIndex++;
1786 void
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:"),
1794 B_GENERIC);
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
1809 int32
1810 MultiAudioNode::_OutputThread()
1812 CALLED();
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,
1822 system_time());
1825 while (atomic_get(&fQuitThread) == 0) {
1826 BAutolock locker(fBufferLock);
1827 // make sure the buffers don't change while we're playing with them
1829 // send buffer
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,
1858 *input);
1861 input->fOldBufferInfo = bufferInfo;
1863 if (input->fBuffer != NULL) {
1864 _FillNextBuffer(*input, input->fBuffer);
1865 input->fBuffer->Recycle();
1866 input->fBuffer = NULL;
1867 } else {
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"));
1873 } else {
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
1889 // buffer
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
1906 // enabled
1907 status_t err = B_ERROR;
1908 if (output->fOutputEnabled) {
1909 err = SendBuffer(buffer, output->fOutput.source,
1910 output->fOutput.destination);
1912 if (err != B_OK) {
1913 buffer->Recycle();
1914 } else {
1915 // track how much media we've delivered so far
1916 size_t numSamples
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;
1926 } else {
1927 //PRINT(("record_buffer_cycle non ok\n"));
1933 return B_OK;
1937 void
1938 MultiAudioNode::_WriteZeros(node_input& input, uint32 bufferCycle)
1940 //CALLED();
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--)
1945 *sample++ = 128;
1946 } else {
1947 int32 *sample = (int32*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base;
1948 for(int32 i = (samples / 4)-1; i>=0; i--)
1949 *sample++ = 0;
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--) {
1963 *(float*)dest = 0;
1964 dest += stride;
1967 break;
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--) {
1974 *(double*)dest = 0;
1975 dest += stride;
1978 break;
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--) {
1985 *(int32*)dest = 0;
1986 dest += stride;
1989 break;
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--) {
1996 *(int16*)dest = 0;
1997 dest += stride;
2000 break;
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;
2008 dest += stride;
2011 break;
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--) {
2018 *(int8*)dest = 0;
2019 dest += stride;
2022 break;
2024 default:
2025 fprintf(stderr, "ERROR in WriteZeros format not handled\n");
2030 void
2031 MultiAudioNode::_FillWithZeros(node_input& input)
2033 CALLED();
2034 for (int32 i = 0; i < fDevice->BufferList().return_playback_buffers; i++)
2035 _WriteZeros(input, i);
2039 void
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);
2050 return;
2053 if (channelCount != input.fFormat.u.raw_audio.channel_count) {
2054 PRINT(("Channel count is different"));
2055 return;
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);
2075 status_t
2076 MultiAudioNode::_StartOutputThreadIfNeeded()
2078 CALLED();
2079 // the thread is already started ?
2080 if (fThread >= 0)
2081 return B_OK;
2083 PublishTime(-50, 0, 0);
2085 fThread = spawn_thread(_OutputThreadEntry, "multi_audio audio output",
2086 B_REAL_TIME_PRIORITY, this);
2087 if (fThread < 0)
2088 return fThread;
2090 resume_thread(fThread);
2091 return B_OK;
2095 status_t
2096 MultiAudioNode::_StopOutputThread()
2098 CALLED();
2099 atomic_set(&fQuitThread, 1);
2101 wait_for_thread(fThread, NULL);
2102 fThread = -1;
2103 return B_OK;
2107 void
2108 MultiAudioNode::_AllocateBuffers(node_output &channel)
2110 CALLED();
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);
2124 void
2125 MultiAudioNode::_UpdateTimeSource(multi_buffer_info& info,
2126 multi_buffer_info& oldInfo, node_input& input)
2128 //CALLED();
2129 if (!fTimeSourceStarted || oldInfo.played_real_time == 0)
2130 return;
2132 fTimeComputer.AddTimeStamp(info.played_real_time,
2133 info.played_frames_count);
2134 PublishTime(fTimeComputer.PerformanceTime(), fTimeComputer.RealTime(),
2135 fTimeComputer.Drift());
2139 BBuffer*
2140 MultiAudioNode::_FillNextBuffer(multi_buffer_info& info, node_output& output)
2142 //CALLED();
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)
2149 return 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
2156 // control thread.
2157 fprintf(stderr, "Buffer is null");
2158 return 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,
2188 bufferSize);
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);
2199 return buffer;
2203 status_t
2204 MultiAudioNode::GetConfigurationFor(BMessage* message)
2206 CALLED();
2207 if (message == NULL)
2208 return B_BAD_VALUE;
2210 size_t bufferSize = 128;
2211 void* buffer = malloc(bufferSize);
2212 if (buffer == NULL)
2213 return B_NO_MEMORY;
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)
2219 continue;
2221 PRINT(("getting parameter %" B_PRIi32 "\n", parameter->ID()));
2222 size_t size = bufferSize;
2223 bigtime_t lastChange;
2224 status_t err;
2225 while ((err = GetParameterValue(parameter->ID(), &lastChange, buffer,
2226 &size)) == B_NO_MEMORY && bufferSize < 128 * 1024) {
2227 bufferSize += 128;
2228 free(buffer);
2229 buffer = malloc(bufferSize);
2230 if (buffer == NULL)
2231 return B_NO_MEMORY;
2234 if (err == B_OK && size > 0) {
2235 message->AddInt32("parameterID", parameter->ID());
2236 message->AddData("parameterData", B_RAW_TYPE, buffer, size, false);
2237 } else {
2238 PRINT(("parameter err: %s\n", strerror(err)));
2242 free(buffer);
2243 PRINT_OBJECT(*message);
2244 return B_OK;
2248 node_output*
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)
2256 break;
2259 if (source != channel->fOutput.source)
2260 return NULL;
2262 return channel;
2266 node_input*
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)
2274 break;
2277 if (dest != channel->fInput.destination)
2278 return NULL;
2280 return channel;
2284 node_input*
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)
2292 break;
2295 if (destinationId != channel->fInput.destination.id)
2296 return NULL;
2298 return channel;
2302 /*static*/ status_t
2303 MultiAudioNode::_OutputThreadEntry(void* data)
2305 CALLED();
2306 return static_cast<MultiAudioNode*>(data)->_OutputThread();
2310 status_t
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)
2316 return B_BAD_VALUE;
2318 BAutolock locker(fBufferLock);
2320 // already set?
2321 if (fDevice->FormatInfo().output.rate == multiAudioRate)
2322 return B_OK;
2324 // set the frame rate on the device
2325 status_t error = fDevice->SetOutputFrameRate(multiAudioRate);
2326 if (error != B_OK)
2327 return error;
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);
2338 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);
2358 return B_OK;
2362 status_t
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)
2368 return B_BAD_VALUE;
2370 BAutolock locker(fBufferLock);
2372 // already set?
2373 if (fDevice->FormatInfo().input.rate == multiAudioRate)
2374 return B_OK;
2376 // set the frame rate on the device
2377 status_t error = fDevice->SetInputFrameRate(multiAudioRate);
2378 if (error != B_OK)
2379 return error;
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);
2390 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);
2410 return B_OK;
2414 void
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);