1 /*
2 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 //! Media add-on for drivers that use the multi audio interface
8
9
10 #include "MultiAudioNode.h"
11
12 #include <stdio.h>
13 #include <string.h>
14
15 #include <Autolock.h>
16 #include <Buffer.h>
17 #include <BufferGroup.h>
18 #include <Catalog.h>
19 #include <ParameterWeb.h>
20 #include <String.h>
21
22 #include <Referenceable.h>
23
24 #include "MultiAudioUtility.h"
25 #ifdef DEBUG
26 # define PRINTING
27 #endif
28 #include "debug.h"
29 #include "Resampler.h"
30
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "MultiAudio"
33
34 #define PARAMETER_ID_INPUT_FREQUENCY 1
35 #define PARAMETER_ID_OUTPUT_FREQUENCY 2
36
37
38 // This represents a hardware output.
39 class node_input {
40 public:
41 node_input(media_input& input, media_format preferredFormat);
42 ~node_input();
43
44 int32 fChannelId;
45 media_input fInput;
46 media_format fPreferredFormat;
47 media_format fFormat;
48
49 volatile uint32 fBufferCycle;
50 int32 fOldBufferCycle;
51 BBuffer* fBuffer;
52 Resampler *fResampler;
53 };
54
55
56 // This represents a hardware input.
57 class node_output {
58 public:
59 node_output(media_output& output, media_format preferredFormat);
60 ~node_output();
61
62 int32 fChannelId;
63 media_output fOutput;
64 media_format fPreferredFormat;
65
66 BBufferGroup* fBufferGroup;
67 bool fOutputEnabled;
68 uint64 fSamplesSent;
69 volatile uint32 fBufferCycle;
70 int32 fOldBufferCycle;
71 Resampler* fResampler;
72 };
73
74
75 struct FrameRateChangeCookie : public BReferenceable {
76 float oldFrameRate;
77 uint32 id;
78 };
79
80
81 struct sample_rate_info {
82 uint32 multiAudioRate;
83 const char* name;
84 };
85
86
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"},
104 {}
105 };
106
107
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")
122 };
123
124
125 // #pragma mark -
126
127
node_input(media_input & input,media_format preferredFormat)128 node_input::node_input(media_input& input, media_format preferredFormat)
129 {
130 CALLED();
131 fInput = input;
132 fPreferredFormat = preferredFormat;
133 fBufferCycle = 1;
134 fOldBufferCycle = -1;
135 fBuffer = NULL;
136 fResampler = NULL;
137 }
138
139
~node_input()140 node_input::~node_input()
141 {
142 CALLED();
143 }
144
145
146 // #pragma mark -
147
148
node_output(media_output & output,media_format preferredFormat)149 node_output::node_output(media_output& output, media_format preferredFormat)
150 :
151 fBufferGroup(NULL),
152 fOutputEnabled(true)
153 {
154 CALLED();
155 fOutput = output;
156 fPreferredFormat = preferredFormat;
157 fBufferCycle = 1;
158 fOldBufferCycle = -1;
159 fResampler = NULL;
160 }
161
162
~node_output()163 node_output::~node_output()
164 {
165 CALLED();
166 }
167
168
169 // #pragma mark -
170
171
MultiAudioNode(BMediaAddOn * addon,const char * name,MultiAudioDevice * device,int32 internalID,BMessage * config)172 MultiAudioNode::MultiAudioNode(BMediaAddOn* addon, const char* name,
173 MultiAudioDevice* device, int32 internalID, BMessage* config)
174 :
175 BMediaNode(name),
176 BBufferConsumer(B_MEDIA_RAW_AUDIO),
177 BBufferProducer(B_MEDIA_RAW_AUDIO),
178 BMediaEventLooper(),
179 fBufferLock("multi audio buffers"),
180 fQuitThread(0),
181 fThread(-1),
182 fDevice(device),
183 fTimeSourceStarted(false),
184 fWeb(NULL),
185 fConfig()
186 {
187 CALLED();
188 fInitStatus = B_NO_INIT;
189
190 if (!device)
191 return;
192
193 fAddOn = addon;
194 fId = internalID;
195
196 if (fDevice->Description().output_channel_count > 0) {
197 // initialize our preferred format objects
198 fOutputPreferredFormat.type = B_MEDIA_RAW_AUDIO;
199 fOutputPreferredFormat.u.raw_audio.format
200 = MultiAudio::convert_to_media_format(
201 fDevice->FormatInfo().output.format);
202 fOutputPreferredFormat.u.raw_audio.valid_bits
203 = MultiAudio::convert_to_valid_bits(
204 fDevice->FormatInfo().output.format);
205 fOutputPreferredFormat.u.raw_audio.channel_count = 2;
206 fOutputPreferredFormat.u.raw_audio.frame_rate
207 = MultiAudio::convert_to_sample_rate(fDevice->FormatInfo().output.rate);
208 // measured in Hertz
209 fOutputPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
210
211 if (fOutputPreferredFormat.u.raw_audio.format != 0) {
212 AddNodeKind(B_PHYSICAL_OUTPUT);
213
214 // we'll use the consumer's preferred buffer size, if any
215 fOutputPreferredFormat.u.raw_audio.buffer_size
216 = fDevice->BufferList().return_playback_buffer_size
217 * (fOutputPreferredFormat.u.raw_audio.format
218 & media_raw_audio_format::B_AUDIO_SIZE_MASK)
219 * fOutputPreferredFormat.u.raw_audio.channel_count;
220 }
221 }
222
223 if (fDevice->Description().input_channel_count > 0) {
224 // initialize our preferred format objects
225 fInputPreferredFormat.type = B_MEDIA_RAW_AUDIO;
226 fInputPreferredFormat.u.raw_audio.format
227 = MultiAudio::convert_to_media_format(
228 fDevice->FormatInfo().input.format);
229 fInputPreferredFormat.u.raw_audio.valid_bits
230 = MultiAudio::convert_to_valid_bits(fDevice->FormatInfo().input.format);
231 fInputPreferredFormat.u.raw_audio.channel_count
232 = fDevice->Description().input_channel_count;
233 fInputPreferredFormat.u.raw_audio.frame_rate
234 = MultiAudio::convert_to_sample_rate(fDevice->FormatInfo().input.rate);
235 // measured in Hertz
236 fInputPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
237
238 if (fInputPreferredFormat.u.raw_audio.format != 0) {
239 AddNodeKind(B_PHYSICAL_INPUT);
240
241 // we'll use the consumer's preferred buffer size, if any
242 fInputPreferredFormat.u.raw_audio.buffer_size
243 = fDevice->BufferList().return_record_buffer_size
244 * (fInputPreferredFormat.u.raw_audio.format
245 & media_raw_audio_format::B_AUDIO_SIZE_MASK)
246 * fInputPreferredFormat.u.raw_audio.channel_count;
247 }
248 }
249
250 if (config != NULL) {
251 fConfig = *config;
252 PRINT_OBJECT(*config);
253 }
254
255 fInitStatus = B_OK;
256 }
257
258
~MultiAudioNode()259 MultiAudioNode::~MultiAudioNode()
260 {
261 CALLED();
262 fAddOn->GetConfigurationFor(this, NULL);
263
264 _StopOutputThread();
265 BMediaEventLooper::Quit();
266 }
267
268
269 status_t
InitCheck() const270 MultiAudioNode::InitCheck() const
271 {
272 CALLED();
273 return fInitStatus;
274 }
275
276
277 void
GetFlavor(flavor_info * info,int32 id)278 MultiAudioNode::GetFlavor(flavor_info* info, int32 id)
279 {
280 CALLED();
281 if (info == NULL)
282 return;
283
284 info->flavor_flags = 0;
285 info->possible_count = 1;
286 // one flavor at a time
287 info->in_format_count = 0;
288 // no inputs
289 info->in_formats = 0;
290 info->out_format_count = 0;
291 // no outputs
292 info->out_formats = 0;
293 info->internal_id = id;
294
295 info->name = const_cast<char*>("MultiAudioNode Node");
296 info->info = const_cast<char*>("The MultiAudioNode node outputs to "
297 "multi_audio drivers.");
298 info->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE
299 | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE;
300 info->in_format_count = 1;
301 // 1 input
302 media_format* inFormats = new media_format[info->in_format_count];
303 GetFormat(&inFormats[0]);
304 info->in_formats = inFormats;
305
306 info->out_format_count = 1;
307 // 1 output
308 media_format* outFormats = new media_format[info->out_format_count];
309 GetFormat(&outFormats[0]);
310 info->out_formats = outFormats;
311 }
312
313
314 void
GetFormat(media_format * format)315 MultiAudioNode::GetFormat(media_format* format)
316 {
317 CALLED();
318 if (format == NULL)
319 return;
320
321 format->type = B_MEDIA_RAW_AUDIO;
322 format->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
323 format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
324 format->u.raw_audio = media_raw_audio_format::wildcard;
325 }
326
327
328 //#pragma mark - BMediaNode
329
330
331 BMediaAddOn*
AddOn(int32 * _internalID) const332 MultiAudioNode::AddOn(int32* _internalID) const
333 {
334 CALLED();
335 // BeBook says this only gets called if we were in an add-on.
336 if (fAddOn != 0 && _internalID != NULL)
337 *_internalID = fId;
338
339 return fAddOn;
340 }
341
342
343 void
Preroll()344 MultiAudioNode::Preroll()
345 {
346 CALLED();
347 // TODO: Performance opportunity
348 BMediaNode::Preroll();
349 }
350
351
352 status_t
HandleMessage(int32 message,const void * data,size_t size)353 MultiAudioNode::HandleMessage(int32 message, const void* data, size_t size)
354 {
355 CALLED();
356 return B_ERROR;
357 }
358
359
360 void
NodeRegistered()361 MultiAudioNode::NodeRegistered()
362 {
363 CALLED();
364
365 if (fInitStatus != B_OK) {
366 ReportError(B_NODE_IN_DISTRESS);
367 return;
368 }
369
370 node_input *currentInput = NULL;
371 int32 currentId = 0;
372
373 for (int32 i = 0; i < fDevice->Description().output_channel_count; i++) {
374 if (currentInput == NULL
375 || (fDevice->Description().channels[i].designations
376 & B_CHANNEL_MONO_BUS) != 0
377 || ((fDevice->Description().channels[currentId].designations
378 & B_CHANNEL_STEREO_BUS) != 0
379 && ((fDevice->Description().channels[i].designations
380 & B_CHANNEL_LEFT) != 0
381 || (fDevice->Description().channels[i].designations
382 & B_CHANNEL_STEREO_BUS) == 0))
383 || ((fDevice->Description().channels[currentId].designations
384 & B_CHANNEL_SURROUND_BUS) != 0
385 && ((fDevice->Description().channels[i].designations
386 & B_CHANNEL_LEFT) != 0
387 || (fDevice->Description().channels[i].designations
388 & B_CHANNEL_SURROUND_BUS) == 0))) {
389 PRINT(("NodeRegistered(): creating an input for %" B_PRIi32 "\n",
390 i));
391 PRINT(("%" B_PRId32 "\t%d\t0x%" B_PRIx32 "\t0x%" B_PRIx32 "\n",
392 fDevice->Description().channels[i].channel_id,
393 fDevice->Description().channels[i].kind,
394 fDevice->Description().channels[i].designations,
395 fDevice->Description().channels[i].connectors));
396
397 media_input* input = new media_input;
398
399 input->format = fOutputPreferredFormat;
400 input->destination.port = ControlPort();
401 input->destination.id = fInputs.CountItems();
402 input->node = Node();
403 sprintf(input->name, "output %" B_PRId32, input->destination.id);
404
405 currentInput = new node_input(*input, fOutputPreferredFormat);
406 currentInput->fPreferredFormat.u.raw_audio.channel_count = 1;
407 currentInput->fFormat = currentInput->fPreferredFormat;
408 currentInput->fInput.format = currentInput->fPreferredFormat;
409
410 delete currentInput->fResampler;
411 currentInput->fResampler = new
412 Resampler(currentInput->fPreferredFormat.AudioFormat(),
413 fOutputPreferredFormat.AudioFormat());
414
415 currentInput->fChannelId
416 = fDevice->Description().channels[i].channel_id;
417 fInputs.AddItem(currentInput);
418
419 currentId = i;
420 } else {
421 PRINT(("NodeRegistered(): adding a channel\n"));
422 currentInput->fPreferredFormat.u.raw_audio.channel_count++;
423 currentInput->fFormat = currentInput->fPreferredFormat;
424 currentInput->fInput.format = currentInput->fPreferredFormat;
425 }
426 currentInput->fInput.format.u.raw_audio.format
427 = media_raw_audio_format::wildcard.format;
428 }
429
430 node_output *currentOutput = NULL;
431 currentId = 0;
432
433 for (int32 i = fDevice->Description().output_channel_count;
434 i < fDevice->Description().output_channel_count
435 + fDevice->Description().input_channel_count; i++) {
436 if (currentOutput == NULL
437 || (fDevice->Description().channels[i].designations
438 & B_CHANNEL_MONO_BUS) != 0
439 || ((fDevice->Description().channels[currentId].designations
440 & B_CHANNEL_STEREO_BUS) != 0
441 && ((fDevice->Description().channels[i].designations
442 & B_CHANNEL_LEFT) != 0
443 || (fDevice->Description().channels[i].designations
444 & B_CHANNEL_STEREO_BUS) == 0))
445 || ((fDevice->Description().channels[currentId].designations
446 & B_CHANNEL_SURROUND_BUS) != 0
447 && ((fDevice->Description().channels[i].designations
448 & B_CHANNEL_LEFT) != 0
449 || (fDevice->Description().channels[i].designations
450 & B_CHANNEL_SURROUND_BUS) == 0))) {
451 PRINT(("NodeRegistered(): creating an output for %" B_PRIi32 "\n",
452 i));
453 PRINT(("%" B_PRId32 "\t%d\t0x%" B_PRIx32 "\t0x%" B_PRIx32 "\n",
454 fDevice->Description().channels[i].channel_id,
455 fDevice->Description().channels[i].kind,
456 fDevice->Description().channels[i].designations,
457 fDevice->Description().channels[i].connectors));
458
459 media_output *output = new media_output;
460
461 output->format = fInputPreferredFormat;
462 output->destination = media_destination::null;
463 output->source.port = ControlPort();
464 output->source.id = fOutputs.CountItems();
465 output->node = Node();
466 sprintf(output->name, "input %" B_PRId32, output->source.id);
467
468 currentOutput = new node_output(*output, fInputPreferredFormat);
469 currentOutput->fPreferredFormat.u.raw_audio.channel_count = 1;
470 currentOutput->fOutput.format = currentOutput->fPreferredFormat;
471
472 delete currentOutput->fResampler;
473 currentOutput->fResampler = new
474 Resampler(fInputPreferredFormat.AudioFormat(),
475 currentOutput->fPreferredFormat.AudioFormat());
476
477 currentOutput->fChannelId
478 = fDevice->Description().channels[i].channel_id;
479 fOutputs.AddItem(currentOutput);
480
481 currentId = i;
482 } else {
483 PRINT(("NodeRegistered(): adding a channel\n"));
484 currentOutput->fPreferredFormat.u.raw_audio.channel_count++;
485 currentOutput->fOutput.format = currentOutput->fPreferredFormat;
486 }
487 }
488
489 // Set up our parameter web
490 fWeb = MakeParameterWeb();
491 SetParameterWeb(fWeb);
492
493 // Apply configuration
494 #ifdef PRINTING
495 bigtime_t start = system_time();
496 #endif
497
498 int32 index = 0;
499 int32 parameterID = 0;
500 const void *data;
501 ssize_t size;
502 while (fConfig.FindInt32("parameterID", index, ¶meterID) == B_OK) {
503 if (fConfig.FindData("parameterData", B_RAW_TYPE, index, &data, &size)
504 == B_OK) {
505 SetParameterValue(parameterID, TimeSource()->Now(), data, size);
506 }
507 index++;
508 }
509
510 PRINT(("apply configuration in: %" B_PRIdBIGTIME "\n",
511 system_time() - start));
512
513 SetPriority(B_REAL_TIME_PRIORITY);
514 Run();
515 }
516
517
518 status_t
RequestCompleted(const media_request_info & info)519 MultiAudioNode::RequestCompleted(const media_request_info& info)
520 {
521 CALLED();
522
523 if (info.what != media_request_info::B_REQUEST_FORMAT_CHANGE)
524 return B_OK;
525
526 FrameRateChangeCookie* cookie
527 = (FrameRateChangeCookie*)info.user_data;
528 if (cookie == NULL)
529 return B_OK;
530
531 BReference<FrameRateChangeCookie> cookieReference(cookie, true);
532
533 // if the request failed, we reset the frame rate
534 if (info.status != B_OK) {
535 if (cookie->id == PARAMETER_ID_INPUT_FREQUENCY) {
536 _SetNodeInputFrameRate(cookie->oldFrameRate);
537 if (fDevice->Description().output_rates & B_SR_SAME_AS_INPUT)
538 _SetNodeOutputFrameRate(cookie->oldFrameRate);
539 } else if (cookie->id == PARAMETER_ID_OUTPUT_FREQUENCY)
540 _SetNodeOutputFrameRate(cookie->oldFrameRate);
541
542 // TODO: If we have multiple connections, we should request to change
543 // the format back!
544 }
545
546 return B_OK;
547 }
548
549
550 void
SetTimeSource(BTimeSource * timeSource)551 MultiAudioNode::SetTimeSource(BTimeSource* timeSource)
552 {
553 CALLED();
554 }
555
556
557 // #pragma mark - BBufferConsumer
558
559
560 status_t
AcceptFormat(const media_destination & dest,media_format * format)561 MultiAudioNode::AcceptFormat(const media_destination& dest,
562 media_format* format)
563 {
564 CALLED();
565
566 // Check to make sure the format is okay, then remove
567 // any wildcards corresponding to our requirements.
568 if (format == NULL)
569 return B_BAD_VALUE;
570
571 node_input *channel = _FindInput(dest);
572 if (channel == NULL)
573 return B_MEDIA_BAD_DESTINATION;
574
575 if (!format_is_compatible(*format, channel->fPreferredFormat))
576 return B_MEDIA_BAD_FORMAT;
577
578 format->SpecializeTo(&channel->fPreferredFormat);
579 return B_OK;
580 }
581
582
583 status_t
GetNextInput(int32 * cookie,media_input * _input)584 MultiAudioNode::GetNextInput(int32* cookie, media_input* _input)
585 {
586 CALLED();
587 if (_input == NULL)
588 return B_BAD_VALUE;
589
590 if (*cookie >= fInputs.CountItems() || *cookie < 0)
591 return B_BAD_INDEX;
592
593 node_input* channel = (node_input*)fInputs.ItemAt(*cookie);
594 *_input = channel->fInput;
595 *cookie += 1;
596 PRINT(("input.format: %" B_PRIu32 "\n",
597 channel->fInput.format.u.raw_audio.format));
598 return B_OK;
599 }
600
601
602 void
DisposeInputCookie(int32 cookie)603 MultiAudioNode::DisposeInputCookie(int32 cookie)
604 {
605 CALLED();
606 // nothing to do since our cookies are just integers
607 }
608
609
610 void
BufferReceived(BBuffer * buffer)611 MultiAudioNode::BufferReceived(BBuffer* buffer)
612 {
613 //CALLED();
614 switch (buffer->Header()->type) {
615 /*case B_MEDIA_PARAMETERS:
616 {
617 status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
618 if (status != B_OK) {
619 fprintf(stderr,"ApplyParameterData in MultiAudioNode::BufferReceived failed\n");
620 }
621 buffer->Recycle();
622 }
623 break;*/
624 case B_MEDIA_RAW_AUDIO:
625 if ((buffer->Flags() & BBuffer::B_SMALL_BUFFER) != 0) {
626 fprintf(stderr, "NOT IMPLEMENTED: B_SMALL_BUFFER in "
627 "MultiAudioNode::BufferReceived\n");
628 // TODO: implement this part
629 buffer->Recycle();
630 } else {
631 media_timed_event event(buffer->Header()->start_time,
632 BTimedEventQueue::B_HANDLE_BUFFER, buffer,
633 BTimedEventQueue::B_RECYCLE_BUFFER);
634 status_t status = EventQueue()->AddEvent(event);
635 if (status != B_OK) {
636 fprintf(stderr, "EventQueue()->AddEvent(event) in "
637 "MultiAudioNode::BufferReceived failed\n");
638 buffer->Recycle();
639 }
640 }
641 break;
642 default:
643 fprintf(stderr, "unexpected buffer type in "
644 "MultiAudioNode::BufferReceived\n");
645 buffer->Recycle();
646 break;
647 }
648 }
649
650
651 void
ProducerDataStatus(const media_destination & forWhom,int32 status,bigtime_t atPerformanceTime)652 MultiAudioNode::ProducerDataStatus(const media_destination& forWhom,
653 int32 status, bigtime_t atPerformanceTime)
654 {
655 node_input* channel = _FindInput(forWhom);
656 if (channel == NULL) {
657 fprintf(stderr, "invalid destination received in "
658 "MultiAudioNode::ProducerDataStatus\n");
659 return;
660 }
661
662 media_timed_event event(atPerformanceTime, BTimedEventQueue::B_DATA_STATUS,
663 &channel->fInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
664 EventQueue()->AddEvent(event);
665 }
666
667
668 status_t
GetLatencyFor(const media_destination & forWhom,bigtime_t * _latency,media_node_id * _timeSource)669 MultiAudioNode::GetLatencyFor(const media_destination& forWhom,
670 bigtime_t* _latency, media_node_id* _timeSource)
671 {
672 CALLED();
673 if (_latency == NULL || _timeSource == NULL)
674 return B_BAD_VALUE;
675
676 node_input* channel = _FindInput(forWhom);
677 if (channel == NULL)
678 return B_MEDIA_BAD_DESTINATION;
679
680 *_latency = EventLatency();
681 *_timeSource = TimeSource()->ID();
682 return B_OK;
683 }
684
685
686 status_t
Connected(const media_source & producer,const media_destination & where,const media_format & with_format,media_input * out_input)687 MultiAudioNode::Connected(const media_source& producer,
688 const media_destination& where, const media_format& with_format,
689 media_input* out_input)
690 {
691 CALLED();
692 if (out_input == 0) {
693 fprintf(stderr, "<- B_BAD_VALUE\n");
694 return B_BAD_VALUE;
695 }
696
697 node_input* channel = _FindInput(where);
698 if (channel == NULL) {
699 fprintf(stderr, "<- B_MEDIA_BAD_DESTINATION\n");
700 return B_MEDIA_BAD_DESTINATION;
701 }
702
703 if (with_format.u.raw_audio.frame_rate <= 0
704 || with_format.u.raw_audio.channel_count <= 0
705 || ((with_format.u.raw_audio.format
706 & media_raw_audio_format::B_AUDIO_SIZE_MASK) == 0))
707 return B_BAD_VALUE;
708
709 _UpdateInternalLatency(with_format);
710
711 // record the agreed upon values
712 channel->fInput.source = producer;
713 channel->fInput.format = with_format;
714 *out_input = channel->fInput;
715
716 _StartOutputThreadIfNeeded();
717
718 return B_OK;
719 }
720
721
722 void
Disconnected(const media_source & producer,const media_destination & where)723 MultiAudioNode::Disconnected(const media_source& producer,
724 const media_destination& where)
725 {
726 CALLED();
727
728 node_input* channel = _FindInput(where);
729 if (channel == NULL || channel->fInput.source != producer)
730 return;
731
732 channel->fInput.source = media_source::null;
733 channel->fInput.format = channel->fPreferredFormat;
734
735 BAutolock locker(fBufferLock);
736 _FillWithZeros(*channel);
737 //GetFormat(&channel->fInput.format);
738 }
739
740
741 status_t
FormatChanged(const media_source & producer,const media_destination & consumer,int32 change_tag,const media_format & format)742 MultiAudioNode::FormatChanged(const media_source& producer,
743 const media_destination& consumer, int32 change_tag,
744 const media_format& format)
745 {
746 CALLED();
747
748 node_input* channel = _FindInput(consumer);
749
750 if (channel==NULL) {
751 fprintf(stderr, "<- B_MEDIA_BAD_DESTINATION\n");
752 return B_MEDIA_BAD_DESTINATION;
753 }
754 if (channel->fInput.source != producer)
755 return B_MEDIA_BAD_SOURCE;
756
757 return B_ERROR;
758 }
759
760
761 status_t
SeekTagRequested(const media_destination & destination,bigtime_t targetTime,uint32 flags,media_seek_tag * _seekTag,bigtime_t * _taggedTime,uint32 * _flags)762 MultiAudioNode::SeekTagRequested(const media_destination& destination,
763 bigtime_t targetTime, uint32 flags, media_seek_tag* _seekTag,
764 bigtime_t* _taggedTime, uint32* _flags)
765 {
766 CALLED();
767 return BBufferConsumer::SeekTagRequested(destination, targetTime, flags,
768 _seekTag, _taggedTime, _flags);
769 }
770
771
772 // #pragma mark - BBufferProducer
773
774
775 status_t
FormatSuggestionRequested(media_type type,int32,media_format * format)776 MultiAudioNode::FormatSuggestionRequested(media_type type, int32 /*quality*/,
777 media_format* format)
778 {
779 // FormatSuggestionRequested() is not necessarily part of the format
780 // negotiation process; it's simply an interrogation -- the caller
781 // wants to see what the node's preferred data format is, given a
782 // suggestion by the caller.
783 CALLED();
784
785 if (format == NULL) {
786 fprintf(stderr, "\tERROR - NULL format pointer passed in!\n");
787 return B_BAD_VALUE;
788 }
789
790 // this is the format we'll be returning (our preferred format)
791 *format = fInputPreferredFormat;
792
793 // a wildcard type is okay; we can specialize it
794 if (type == B_MEDIA_UNKNOWN_TYPE)
795 type = B_MEDIA_RAW_AUDIO;
796
797 // we only support raw audio
798 if (type != B_MEDIA_RAW_AUDIO)
799 return B_MEDIA_BAD_FORMAT;
800
801 return B_OK;
802 }
803
804
805 status_t
FormatProposal(const media_source & output,media_format * format)806 MultiAudioNode::FormatProposal(const media_source& output, media_format* format)
807 {
808 // FormatProposal() is the first stage in the BMediaRoster::Connect()
809 // process. We hand out a suggested format, with wildcards for any
810 // variations we support.
811 CALLED();
812
813 // is this a proposal for our select output?
814 node_output* channel = _FindOutput(output);
815 if (channel == NULL) {
816 fprintf(stderr, "MultiAudioNode::FormatProposal returning "
817 "B_MEDIA_BAD_SOURCE\n");
818 return B_MEDIA_BAD_SOURCE;
819 }
820
821 // We only support floating-point raw audio, so we always return that,
822 // but we supply an error code depending on whether we found the proposal
823 // acceptable.
824 media_type requestedType = format->type;
825 *format = channel->fPreferredFormat;
826 if (requestedType != B_MEDIA_UNKNOWN_TYPE
827 && requestedType != B_MEDIA_RAW_AUDIO) {
828 fprintf(stderr, "MultiAudioNode::FormatProposal returning "
829 "B_MEDIA_BAD_FORMAT\n");
830 return B_MEDIA_BAD_FORMAT;
831 }
832 // raw audio or wildcard type, either is okay by us
833 return B_OK;
834 }
835
836
837 status_t
FormatChangeRequested(const media_source & source,const media_destination & destination,media_format * format,int32 * _deprecated_)838 MultiAudioNode::FormatChangeRequested(const media_source& source,
839 const media_destination& destination, media_format* format,
840 int32* _deprecated_)
841 {
842 CALLED();
843
844 // we don't support any other formats, so we just reject any format changes.
845 return B_ERROR;
846 }
847
848
849 status_t
GetNextOutput(int32 * cookie,media_output * _output)850 MultiAudioNode::GetNextOutput(int32* cookie, media_output* _output)
851 {
852 CALLED();
853
854 if (*cookie < fOutputs.CountItems() && *cookie >= 0) {
855 node_output* channel = (node_output*)fOutputs.ItemAt(*cookie);
856 *_output = channel->fOutput;
857 *cookie += 1;
858 return B_OK;
859 }
860 return B_BAD_INDEX;
861 }
862
863
864 status_t
DisposeOutputCookie(int32 cookie)865 MultiAudioNode::DisposeOutputCookie(int32 cookie)
866 {
867 CALLED();
868 // do nothing because we don't use the cookie for anything special
869 return B_OK;
870 }
871
872
873 status_t
SetBufferGroup(const media_source & forSource,BBufferGroup * newGroup)874 MultiAudioNode::SetBufferGroup(const media_source& forSource,
875 BBufferGroup* newGroup)
876 {
877 CALLED();
878
879 // is this our output?
880 node_output* channel = _FindOutput(forSource);
881 if (channel == NULL) {
882 fprintf(stderr, "MultiAudioNode::SetBufferGroup returning "
883 "B_MEDIA_BAD_SOURCE\n");
884 return B_MEDIA_BAD_SOURCE;
885 }
886
887 // Are we being passed the buffer group we're already using?
888 if (newGroup == channel->fBufferGroup)
889 return B_OK;
890
891 // Ahh, someone wants us to use a different buffer group. At this point
892 // we delete the one we are using and use the specified one instead.
893 // If the specified group is NULL, we need to recreate one ourselves, and
894 // use *that*. Note that if we're caching a BBuffer that we requested
895 // earlier, we have to Recycle() that buffer *before* deleting the buffer
896 // group, otherwise we'll deadlock waiting for that buffer to be recycled!
897 delete channel->fBufferGroup;
898 // waits for all buffers to recycle
899 if (newGroup != NULL) {
900 // we were given a valid group; just use that one from now on
901 channel->fBufferGroup = newGroup;
902 } else {
903 // we were passed a NULL group pointer; that means we construct
904 // our own buffer group to use from now on
905 size_t size = channel->fOutput.format.u.raw_audio.buffer_size;
906 int32 count = int32(fLatency / BufferDuration() + 1 + 1);
907 BBufferGroup* group = new BBufferGroup(size, count);
908 if (group == NULL || group->InitCheck() != B_OK) {
909 delete group;
910 fprintf(stderr, "MultiAudioNode::SetBufferGroup failed to"
911 "instantiate a new group.\n");
912 return B_ERROR;
913 }
914 channel->fBufferGroup = group;
915 }
916
917 return B_OK;
918 }
919
920
921 status_t
PrepareToConnect(const media_source & what,const media_destination & where,media_format * format,media_source * source,char * name)922 MultiAudioNode::PrepareToConnect(const media_source& what,
923 const media_destination& where, media_format* format,
924 media_source* source, char* name)
925 {
926 CALLED();
927
928 // is this our output?
929 node_output* channel = _FindOutput(what);
930 if (channel == NULL) {
931 fprintf(stderr, "MultiAudioNode::PrepareToConnect returning "
932 "B_MEDIA_BAD_SOURCE\n");
933 return B_MEDIA_BAD_SOURCE;
934 }
935
936 // are we already connected?
937 if (channel->fOutput.destination != media_destination::null)
938 return B_MEDIA_ALREADY_CONNECTED;
939
940 // Allow buffer sizes other than our preferred one.
941 media_format compatible = channel->fPreferredFormat;
942 compatible.u.raw_audio.buffer_size
943 = media_raw_audio_format::wildcard.buffer_size;
944
945 if (!format_is_compatible(*format, compatible))
946 return B_MEDIA_BAD_FORMAT;
947
948 format->SpecializeTo(&channel->fPreferredFormat);
949
950 // Now reserve the connection, and return information about it
951 channel->fOutput.destination = where;
952 channel->fOutput.format = *format;
953
954 *source = channel->fOutput.source;
955 strlcpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
956 return B_OK;
957 }
958
959
960 void
Connect(status_t error,const media_source & source,const media_destination & destination,const media_format & format,char * name)961 MultiAudioNode::Connect(status_t error, const media_source& source,
962 const media_destination& destination, const media_format& format,
963 char* name)
964 {
965 CALLED();
966
967 // is this our output?
968 node_output* channel = _FindOutput(source);
969 if (channel == NULL) {
970 fprintf(stderr, "MultiAudioNode::Connect returning (cause: "
971 "B_MEDIA_BAD_SOURCE)\n");
972 return;
973 }
974
975 // If something earlier failed, Connect() might still be called, but with
976 // a non-zero error code. When that happens we simply unreserve the
977 // connection and do nothing else.
978 if (error != B_OK) {
979 channel->fOutput.destination = media_destination::null;
980 channel->fOutput.format = channel->fPreferredFormat;
981 return;
982 }
983
984 // Okay, the connection has been confirmed. Record the destination and
985 // format that we agreed on, and report our connection name again.
986 channel->fOutput.destination = destination;
987 channel->fOutput.format = format;
988 strlcpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH);
989
990 // reset our buffer duration, etc. to avoid later calculations
991 bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000
992 / ((channel->fOutput.format.u.raw_audio.format
993 & media_raw_audio_format::B_AUDIO_SIZE_MASK)
994 * channel->fOutput.format.u.raw_audio.channel_count)
995 / ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100));
996
997 SetBufferDuration(duration);
998
999 // Now that we're connected, we can determine our downstream latency.
1000 // Do so, then make sure we get our events early enough.
1001 media_node_id id;
1002 FindLatencyFor(channel->fOutput.destination, &fLatency, &id);
1003 PRINT(("\tdownstream latency = %" B_PRIdBIGTIME "\n", fLatency));
1004
1005 fInternalLatency = BufferDuration();
1006 PRINT(("\tbuffer-filling took %" B_PRIdBIGTIME " usec on this machine\n",
1007 fInternalLatency));
1008 //SetEventLatency(fLatency + fInternalLatency);
1009
1010 // Set up the buffer group for our connection, as long as nobody handed us
1011 // a buffer group (via SetBufferGroup()) prior to this. That can happen,
1012 // for example, if the consumer calls SetOutputBuffersFor() on us from
1013 // within its Connected() method.
1014 if (channel->fBufferGroup == NULL)
1015 _AllocateBuffers(*channel);
1016
1017 _StartOutputThreadIfNeeded();
1018 }
1019
1020
1021 void
Disconnect(const media_source & what,const media_destination & where)1022 MultiAudioNode::Disconnect(const media_source& what,
1023 const media_destination& where)
1024 {
1025 CALLED();
1026
1027 // is this our output?
1028 node_output* channel = _FindOutput(what);
1029 if (channel == NULL) {
1030 fprintf(stderr, "MultiAudioNode::Disconnect() returning (cause: "
1031 "B_MEDIA_BAD_SOURCE)\n");
1032 return;
1033 }
1034
1035 // Make sure that our connection is the one being disconnected
1036 if (where == channel->fOutput.destination
1037 && what == channel->fOutput.source) {
1038 channel->fOutput.destination = media_destination::null;
1039 channel->fOutput.format = channel->fPreferredFormat;
1040 delete channel->fBufferGroup;
1041 channel->fBufferGroup = NULL;
1042 } else {
1043 fprintf(stderr, "\tDisconnect() called with wrong source/destination ("
1044 "%" B_PRId32 "/%" B_PRId32 "), ours is (%" B_PRId32 "/%" B_PRId32
1045 ")\n", what.id, where.id, channel->fOutput.source.id,
1046 channel->fOutput.destination.id);
1047 }
1048 }
1049
1050
1051 void
LateNoticeReceived(const media_source & what,bigtime_t howMuch,bigtime_t performanceTime)1052 MultiAudioNode::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
1053 bigtime_t performanceTime)
1054 {
1055 CALLED();
1056
1057 // is this our output?
1058 node_output* channel = _FindOutput(what);
1059 if (channel == NULL)
1060 return;
1061
1062 // If we're late, we need to catch up. Respond in a manner appropriate
1063 // to our current run mode.
1064 if (RunMode() == B_RECORDING) {
1065 // A hardware capture node can't adjust; it simply emits buffers at
1066 // appropriate points. We (partially) simulate this by not adjusting
1067 // our behavior upon receiving late notices -- after all, the hardware
1068 // can't choose to capture "sooner"....
1069 } else if (RunMode() == B_INCREASE_LATENCY) {
1070 // We're late, and our run mode dictates that we try to produce buffers
1071 // earlier in order to catch up. This argues that the downstream nodes
1072 // are not properly reporting their latency, but there's not much we can
1073 // do about that at the moment, so we try to start producing buffers
1074 // earlier to compensate.
1075 fInternalLatency += howMuch;
1076 SetEventLatency(fLatency + fInternalLatency);
1077
1078 fprintf(stderr, "\tincreasing latency to %" B_PRIdBIGTIME"\n",
1079 fLatency + fInternalLatency);
1080 } else {
1081 // The other run modes dictate various strategies for sacrificing data
1082 // quality in the interests of timely data delivery. The way *we* do
1083 // this is to skip a buffer, which catches us up in time by one buffer
1084 // duration.
1085 /*size_t nSamples = fOutput.format.u.raw_audio.buffer_size / sizeof(float);
1086 mSamplesSent += nSamples;*/
1087
1088 fprintf(stderr, "\tskipping a buffer to try to catch up\n");
1089 }
1090 }
1091
1092
1093 void
EnableOutput(const media_source & what,bool enabled,int32 * _deprecated_)1094 MultiAudioNode::EnableOutput(const media_source& what, bool enabled,
1095 int32* _deprecated_)
1096 {
1097 CALLED();
1098
1099 // If I had more than one output, I'd have to walk my list of output
1100 // records to see which one matched the given source, and then
1101 // enable/disable that one. But this node only has one output, so I
1102 // just make sure the given source matches, then set the enable state
1103 // accordingly.
1104 node_output* channel = _FindOutput(what);
1105 if (channel != NULL)
1106 channel->fOutputEnabled = enabled;
1107 }
1108
1109
1110 void
AdditionalBufferRequested(const media_source & source,media_buffer_id previousBuffer,bigtime_t previousTime,const media_seek_tag * previousTag)1111 MultiAudioNode::AdditionalBufferRequested(const media_source& source,
1112 media_buffer_id previousBuffer, bigtime_t previousTime,
1113 const media_seek_tag* previousTag)
1114 {
1115 CALLED();
1116 // we don't support offline mode
1117 return;
1118 }
1119
1120
1121 // #pragma mark - BMediaEventLooper
1122
1123
1124 void
HandleEvent(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1125 MultiAudioNode::HandleEvent(const media_timed_event* event, bigtime_t lateness,
1126 bool realTimeEvent)
1127 {
1128 switch (event->type) {
1129 case BTimedEventQueue::B_START:
1130 _HandleStart(event, lateness, realTimeEvent);
1131 break;
1132 case BTimedEventQueue::B_SEEK:
1133 _HandleSeek(event, lateness, realTimeEvent);
1134 break;
1135 case BTimedEventQueue::B_WARP:
1136 _HandleWarp(event, lateness, realTimeEvent);
1137 break;
1138 case BTimedEventQueue::B_STOP:
1139 _HandleStop(event, lateness, realTimeEvent);
1140 break;
1141 case BTimedEventQueue::B_HANDLE_BUFFER:
1142 if (RunState() == BMediaEventLooper::B_STARTED)
1143 _HandleBuffer(event, lateness, realTimeEvent);
1144 break;
1145 case BTimedEventQueue::B_DATA_STATUS:
1146 _HandleDataStatus(event, lateness, realTimeEvent);
1147 break;
1148 case BTimedEventQueue::B_PARAMETER:
1149 _HandleParameter(event, lateness, realTimeEvent);
1150 break;
1151 default:
1152 fprintf(stderr," unknown event type: %" B_PRId32 "\n",
1153 event->type);
1154 break;
1155 }
1156 }
1157
1158
1159 status_t
_HandleBuffer(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1160 MultiAudioNode::_HandleBuffer(const media_timed_event* event,
1161 bigtime_t lateness, bool realTimeEvent)
1162 {
1163 BBuffer* buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
1164 if (buffer == NULL)
1165 return B_BAD_VALUE;
1166
1167 //PRINT(("buffer->Header()->destination: %i\n", buffer->Header()->destination));
1168
1169 node_input* channel = _FindInput(buffer->Header()->destination);
1170 if (channel == NULL) {
1171 buffer->Recycle();
1172 return B_MEDIA_BAD_DESTINATION;
1173 }
1174
1175 // if the buffer is late, we ignore it and report the fact to the producer
1176 // who sent it to us
1177 if (RunMode() != B_OFFLINE && RunMode() != B_RECORDING && lateness > 0) {
1178 // lateness doesn't matter in offline mode or in recording mode
1179 //mLateBuffers++;
1180 NotifyLateProducer(channel->fInput.source, lateness, event->event_time);
1181 fprintf(stderr," <- LATE BUFFER: %" B_PRIdBIGTIME "\n", lateness);
1182 buffer->Recycle();
1183 } else {
1184 //WriteBuffer(buffer, *channel);
1185 // TODO: This seems like a very fragile mechanism to wait until
1186 // the previous buffer for this channel has been processed...
1187 if (channel->fBuffer != NULL) {
1188 PRINT(("MultiAudioNode::HandleBuffer snoozing recycling channelId: "
1189 "%" B_PRIi32 ", lateness:%" B_PRIdBIGTIME "\n",
1190 channel->fChannelId, lateness));
1191 //channel->fBuffer->Recycle();
1192 snooze(100);
1193 if (channel->fBuffer != NULL)
1194 buffer->Recycle();
1195 else
1196 channel->fBuffer = buffer;
1197 } else {
1198 //PRINT(("MultiAudioNode::HandleBuffer writing channelId: %li, how_early:%lld\n", channel->fChannelId, howEarly));
1199 channel->fBuffer = buffer;
1200 }
1201 }
1202 return B_OK;
1203 }
1204
1205
1206 status_t
_HandleDataStatus(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1207 MultiAudioNode::_HandleDataStatus(const media_timed_event* event,
1208 bigtime_t lateness, bool realTimeEvent)
1209 {
1210 PRINT(("MultiAudioNode::HandleDataStatus status:%" B_PRIi32 ", lateness:%"
1211 B_PRIiBIGTIME "\n", event->data, lateness));
1212 switch (event->data) {
1213 case B_DATA_NOT_AVAILABLE:
1214 break;
1215 case B_DATA_AVAILABLE:
1216 break;
1217 case B_PRODUCER_STOPPED:
1218 break;
1219 default:
1220 break;
1221 }
1222 return B_OK;
1223 }
1224
1225
1226 status_t
_HandleStart(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1227 MultiAudioNode::_HandleStart(const media_timed_event* event, bigtime_t lateness,
1228 bool realTimeEvent)
1229 {
1230 CALLED();
1231 if (RunState() != B_STARTED) {
1232 }
1233 return B_OK;
1234 }
1235
1236
1237 status_t
_HandleSeek(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1238 MultiAudioNode::_HandleSeek(const media_timed_event* event, bigtime_t lateness,
1239 bool realTimeEvent)
1240 {
1241 CALLED();
1242 PRINT(("MultiAudioNode::HandleSeek(t=%" B_PRIdBIGTIME ",d=%" B_PRIi32
1243 ",bd=%" B_PRId64 ")\n",
1244 event->event_time,event->data,event->bigdata));
1245 return B_OK;
1246 }
1247
1248
1249 status_t
_HandleWarp(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1250 MultiAudioNode::_HandleWarp(const media_timed_event* event, bigtime_t lateness,
1251 bool realTimeEvent)
1252 {
1253 CALLED();
1254 return B_OK;
1255 }
1256
1257
1258 status_t
_HandleStop(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1259 MultiAudioNode::_HandleStop(const media_timed_event* event, bigtime_t lateness,
1260 bool realTimeEvent)
1261 {
1262 CALLED();
1263 // flush the queue so downstreamers don't get any more
1264 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
1265 BTimedEventQueue::B_HANDLE_BUFFER);
1266
1267 //_StopOutputThread();
1268 return B_OK;
1269 }
1270
1271
1272 status_t
_HandleParameter(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)1273 MultiAudioNode::_HandleParameter(const media_timed_event* event,
1274 bigtime_t lateness, bool realTimeEvent)
1275 {
1276 CALLED();
1277 return B_OK;
1278 }
1279
1280
1281 // #pragma mark - BTimeSource
1282
1283
1284 void
SetRunMode(run_mode mode)1285 MultiAudioNode::SetRunMode(run_mode mode)
1286 {
1287 CALLED();
1288 PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode));
1289 //BTimeSource::SetRunMode(mode);
1290 }
1291
1292
1293 status_t
TimeSourceOp(const time_source_op_info & op,void * _reserved)1294 MultiAudioNode::TimeSourceOp(const time_source_op_info& op, void* _reserved)
1295 {
1296 CALLED();
1297 switch (op.op) {
1298 case B_TIMESOURCE_START:
1299 PRINT(("TimeSourceOp op B_TIMESOURCE_START\n"));
1300 if (RunState() != BMediaEventLooper::B_STARTED) {
1301 fTimeSourceStarted = true;
1302 _StartOutputThreadIfNeeded();
1303
1304 media_timed_event startEvent(0, BTimedEventQueue::B_START);
1305 EventQueue()->AddEvent(startEvent);
1306 }
1307 break;
1308 case B_TIMESOURCE_STOP:
1309 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP\n"));
1310 if (RunState() == BMediaEventLooper::B_STARTED) {
1311 media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
1312 EventQueue()->AddEvent(stopEvent);
1313 fTimeSourceStarted = false;
1314 _StopOutputThread();
1315 PublishTime(0, 0, 1.0f);
1316 }
1317 break;
1318 case B_TIMESOURCE_STOP_IMMEDIATELY:
1319 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP_IMMEDIATELY\n"));
1320 if (RunState() == BMediaEventLooper::B_STARTED) {
1321 media_timed_event stopEvent(0, BTimedEventQueue::B_STOP);
1322 EventQueue()->AddEvent(stopEvent);
1323 fTimeSourceStarted = false;
1324 _StopOutputThread();
1325 PublishTime(0, 0, 1.0f);
1326 }
1327 break;
1328 case B_TIMESOURCE_SEEK:
1329 PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n"));
1330 BroadcastTimeWarp(op.real_time, op.performance_time);
1331 break;
1332 default:
1333 break;
1334 }
1335 return B_OK;
1336 }
1337
1338
1339 // #pragma mark - BControllable
1340
1341
1342 status_t
GetParameterValue(int32 id,bigtime_t * lastChange,void * value,size_t * size)1343 MultiAudioNode::GetParameterValue(int32 id, bigtime_t* lastChange, void* value,
1344 size_t* size)
1345 {
1346 CALLED();
1347
1348 PRINT(("id: %" B_PRIi32 "\n", id));
1349 BParameter* parameter = NULL;
1350 for (int32 i = 0; i < fWeb->CountParameters(); i++) {
1351 parameter = fWeb->ParameterAt(i);
1352 if (parameter->ID() == id)
1353 break;
1354 }
1355
1356 if (parameter == NULL) {
1357 // Hmmm, we were asked for a parameter that we don't actually
1358 // support. Report an error back to the caller.
1359 PRINT(("\terror - asked for illegal parameter %" B_PRId32 "\n", id));
1360 return B_ERROR;
1361 }
1362
1363 if (id == PARAMETER_ID_INPUT_FREQUENCY
1364 || id == PARAMETER_ID_OUTPUT_FREQUENCY) {
1365 const multi_format_info& info = fDevice->FormatInfo();
1366
1367 uint32 rate = id == PARAMETER_ID_INPUT_FREQUENCY
1368 ? info.input.rate : info.output.rate;
1369
1370 if (*size < sizeof(rate))
1371 return B_ERROR;
1372
1373 memcpy(value, &rate, sizeof(rate));
1374 *size = sizeof(rate);
1375 return B_OK;
1376 }
1377
1378 multi_mix_value_info info;
1379 multi_mix_value values[2];
1380 info.values = values;
1381 info.item_count = 0;
1382 multi_mix_control* controls = fDevice->MixControlInfo().controls;
1383 int32 control_id = controls[id - 100].id;
1384
1385 if (*size < sizeof(float))
1386 return B_ERROR;
1387
1388 if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) {
1389 info.item_count = 1;
1390 values[0].id = control_id;
1391
1392 if (parameter->CountChannels() == 2) {
1393 if (*size < 2*sizeof(float))
1394 return B_ERROR;
1395 info.item_count = 2;
1396 values[1].id = controls[id + 1 - 100].id;
1397 }
1398 } else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) {
1399 info.item_count = 1;
1400 values[0].id = control_id;
1401 }
1402
1403 if (info.item_count > 0) {
1404 status_t status = fDevice->GetMix(&info);
1405 if (status != B_OK) {
1406 fprintf(stderr, "Failed on DRIVER_GET_MIX\n");
1407 } else {
1408 if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) {
1409 ((float*)value)[0] = values[0].gain;
1410 *size = sizeof(float);
1411
1412 if (parameter->CountChannels() == 2) {
1413 ((float*)value)[1] = values[1].gain;
1414 *size = 2*sizeof(float);
1415 }
1416
1417 for (uint32 i = 0; i < *size / sizeof(float); i++) {
1418 PRINT(("GetParameterValue B_CONTINUOUS_PARAMETER value[%"
1419 B_PRIi32 "]: %f\n", i, ((float*)value)[i]));
1420 }
1421 } else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) {
1422 BDiscreteParameter* discrete = (BDiscreteParameter*)parameter;
1423 if (discrete->CountItems() <= 2)
1424 ((int32*)value)[0] = values[0].enable ? 1 : 0;
1425 else
1426 ((int32*)value)[0] = values[0].mux;
1427
1428 *size = sizeof(int32);
1429
1430 for (uint32 i = 0; i < *size / sizeof(int32); i++) {
1431 PRINT(("GetParameterValue B_DISCRETE_PARAMETER value[%"
1432 B_PRIi32 "]: %" B_PRIi32 "\n", i, ((int32*)value)[i]));
1433 }
1434 }
1435 }
1436 }
1437 return B_OK;
1438 }
1439
1440
1441 void
SetParameterValue(int32 id,bigtime_t performanceTime,const void * value,size_t size)1442 MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime,
1443 const void* value, size_t size)
1444 {
1445 CALLED();
1446 PRINT(("id: %" B_PRIi32 ", performance_time: %" B_PRIdBIGTIME
1447 ", size: %" B_PRIuSIZE "\n", id, performanceTime, size));
1448
1449 BParameter* parameter = NULL;
1450 for (int32 i = 0; i < fWeb->CountParameters(); i++) {
1451 parameter = fWeb->ParameterAt(i);
1452 if (parameter->ID() == id)
1453 break;
1454 }
1455
1456 if (parameter == NULL)
1457 return;
1458
1459 if (id == PARAMETER_ID_OUTPUT_FREQUENCY
1460 || (id == PARAMETER_ID_INPUT_FREQUENCY
1461 && (fDevice->Description().output_rates
1462 & B_SR_SAME_AS_INPUT) != 0)) {
1463 uint32 rate;
1464 if (size < sizeof(rate))
1465 return;
1466 memcpy(&rate, value, sizeof(rate));
1467
1468 if (rate == fOutputPreferredFormat.u.raw_audio.frame_rate)
1469 return;
1470
1471 // create a cookie RequestCompleted() can get the old frame rate from,
1472 // if anything goes wrong
1473 FrameRateChangeCookie* cookie = new(std::nothrow) FrameRateChangeCookie;
1474 if (cookie == NULL)
1475 return;
1476
1477 cookie->oldFrameRate = fOutputPreferredFormat.u.raw_audio.frame_rate;
1478 cookie->id = id;
1479 BReference<FrameRateChangeCookie> cookieReference(cookie, true);
1480
1481 // NOTE: What we should do is call RequestFormatChange() for all
1482 // connections and change the device's format in RequestCompleted().
1483 // Unfortunately we need the new buffer size first, which we only get
1484 // from the device after changing the format. So we do that now and
1485 // reset it in RequestCompleted(), if something went wrong. This causes
1486 // the buffers we receive until then to be played incorrectly leading
1487 // to unpleasant noise.
1488 float frameRate = MultiAudio::convert_to_sample_rate(rate);
1489 if (_SetNodeInputFrameRate(frameRate) != B_OK)
1490 return;
1491
1492 for (int32 i = 0; i < fInputs.CountItems(); i++) {
1493 node_input* channel = (node_input*)fInputs.ItemAt(i);
1494 if (channel->fInput.source == media_source::null)
1495 continue;
1496
1497 media_format newFormat = channel->fInput.format;
1498 newFormat.u.raw_audio.frame_rate = frameRate;
1499 newFormat.u.raw_audio.buffer_size
1500 = fOutputPreferredFormat.u.raw_audio.buffer_size;
1501
1502 int32 changeTag = 0;
1503 status_t error = RequestFormatChange(channel->fInput.source,
1504 channel->fInput.destination, newFormat, NULL, &changeTag);
1505 if (error == B_OK)
1506 cookie->AcquireReference();
1507 }
1508
1509 if (id != PARAMETER_ID_INPUT_FREQUENCY)
1510 return;
1511 //Do not return cause we should go in the next if
1512 }
1513
1514 if (id == PARAMETER_ID_INPUT_FREQUENCY) {
1515 uint32 rate;
1516 if (size < sizeof(rate))
1517 return;
1518 memcpy(&rate, value, sizeof(rate));
1519
1520 if (rate == fInputPreferredFormat.u.raw_audio.frame_rate)
1521 return;
1522
1523 // create a cookie RequestCompleted() can get the old frame rate from,
1524 // if anything goes wrong
1525 FrameRateChangeCookie* cookie = new(std::nothrow) FrameRateChangeCookie;
1526 if (cookie == NULL)
1527 return;
1528
1529 cookie->oldFrameRate = fInputPreferredFormat.u.raw_audio.frame_rate;
1530 cookie->id = id;
1531 BReference<FrameRateChangeCookie> cookieReference(cookie, true);
1532
1533 // NOTE: What we should do is call RequestFormatChange() for all
1534 // connections and change the device's format in RequestCompleted().
1535 // Unfortunately we need the new buffer size first, which we only get
1536 // from the device after changing the format. So we do that now and
1537 // reset it in RequestCompleted(), if something went wrong. This causes
1538 // the buffers we receive until then to be played incorrectly leading
1539 // to unpleasant noise.
1540 float frameRate = MultiAudio::convert_to_sample_rate(rate);
1541 if (_SetNodeOutputFrameRate(frameRate) != B_OK)
1542 return;
1543
1544 for (int32 i = 0; i < fOutputs.CountItems(); i++) {
1545 node_output* channel = (node_output*)fOutputs.ItemAt(i);
1546 if (channel->fOutput.source == media_source::null)
1547 continue;
1548
1549 media_format newFormat = channel->fOutput.format;
1550 newFormat.u.raw_audio.frame_rate = frameRate;
1551 newFormat.u.raw_audio.buffer_size
1552 = fInputPreferredFormat.u.raw_audio.buffer_size;
1553
1554 int32 changeTag = 0;
1555 status_t error = RequestFormatChange(channel->fOutput.source,
1556 channel->fOutput.destination, newFormat, NULL, &changeTag);
1557 if (error == B_OK)
1558 cookie->AcquireReference();
1559 }
1560
1561 return;
1562 }
1563
1564 multi_mix_value_info info;
1565 multi_mix_value values[2];
1566 info.values = values;
1567 info.item_count = 0;
1568 multi_mix_control* controls = fDevice->MixControlInfo().controls;
1569 int32 control_id = controls[id - 100].id;
1570
1571 if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) {
1572 for (uint32 i = 0; i < size / sizeof(float); i++) {
1573 PRINT(("SetParameterValue B_CONTINUOUS_PARAMETER value[%" B_PRIi32
1574 "]: %f\n", i, ((float*)value)[i]));
1575 }
1576 info.item_count = 1;
1577 values[0].id = control_id;
1578 values[0].gain = ((float*)value)[0];
1579
1580 if (parameter->CountChannels() == 2) {
1581 info.item_count = 2;
1582 values[1].id = controls[id + 1 - 100].id;
1583 values[1].gain = ((float*)value)[1];
1584 }
1585 } else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) {
1586 for (uint32 i = 0; i < size / sizeof(int32); i++) {
1587 PRINT(("SetParameterValue B_DISCRETE_PARAMETER value[%" B_PRIi32
1588 "]: %" B_PRIi32 "\n", i, ((int32*)value)[i]));
1589 }
1590
1591 BDiscreteParameter* discrete = (BDiscreteParameter*)parameter;
1592 if (discrete->CountItems() <= 2) {
1593 info.item_count = 1;
1594 values[0].id = control_id;
1595 values[0].enable = ((int32*)value)[0] == 1;
1596 } else {
1597 info.item_count = 1;
1598 values[0].id = control_id;
1599 values[0].mux = ((uint32*)value)[0];
1600 }
1601 }
1602
1603 if (info.item_count > 0) {
1604 status_t status = fDevice->SetMix(&info);
1605 if (status != B_OK)
1606 fprintf(stderr, "Failed on DRIVER_SET_MIX\n");
1607 }
1608 }
1609
1610
1611 BParameterWeb*
MakeParameterWeb()1612 MultiAudioNode::MakeParameterWeb()
1613 {
1614 CALLED();
1615 BParameterWeb* web = new BParameterWeb();
1616
1617 PRINT(("MixControlInfo().control_count: %" B_PRIi32 "\n",
1618 fDevice->MixControlInfo().control_count));
1619
1620 BParameterGroup* generalGroup = web->MakeGroup(B_TRANSLATE("General"));
1621
1622 const multi_description& description = fDevice->Description();
1623
1624 if ((description.output_rates & B_SR_SAME_AS_INPUT) != 0) {
1625 _CreateFrequencyParameterGroup(generalGroup,
1626 B_TRANSLATE("Input & Output"), PARAMETER_ID_INPUT_FREQUENCY,
1627 description.input_rates);
1628 } else {
1629 _CreateFrequencyParameterGroup(generalGroup, B_TRANSLATE("Input"),
1630 PARAMETER_ID_INPUT_FREQUENCY, description.input_rates);
1631 _CreateFrequencyParameterGroup(generalGroup, B_TRANSLATE("Output"),
1632 PARAMETER_ID_OUTPUT_FREQUENCY, description.output_rates);
1633 }
1634
1635 multi_mix_control* controls = fDevice->MixControlInfo().controls;
1636
1637 for (int i = 0; i < fDevice->MixControlInfo().control_count; i++) {
1638 if ((controls[i].flags & B_MULTI_MIX_GROUP) != 0
1639 && controls[i].parent == 0) {
1640 PRINT(("NEW_GROUP\n"));
1641 BParameterGroup* child = web->MakeGroup(
1642 _GetControlName(controls[i]));
1643
1644 int32 numParameters = 0;
1645 _ProcessGroup(child, i, numParameters);
1646 }
1647 }
1648
1649 return web;
1650 }
1651
1652
1653 const char*
_GetControlName(multi_mix_control & control)1654 MultiAudioNode::_GetControlName(multi_mix_control& control)
1655 {
1656 if (control.string > S_null && (size_t)control.string < B_COUNT_OF(kMultiControlString))
1657 return kMultiControlString[control.string];
1658
1659 return control.name;
1660 }
1661
1662
1663 void
_ProcessGroup(BParameterGroup * group,int32 index,int32 & numParameters)1664 MultiAudioNode::_ProcessGroup(BParameterGroup* group, int32 index,
1665 int32& numParameters)
1666 {
1667 CALLED();
1668 multi_mix_control* parent = &fDevice->MixControlInfo().controls[index];
1669 multi_mix_control* controls = fDevice->MixControlInfo().controls;
1670
1671 for (int32 i = 0; i < fDevice->MixControlInfo().control_count; i++) {
1672 if (controls[i].parent != parent->id)
1673 continue;
1674
1675 const char* name = _GetControlName(controls[i]);
1676
1677 if (controls[i].flags & B_MULTI_MIX_GROUP) {
1678 PRINT(("NEW_GROUP\n"));
1679 BParameterGroup* child = group->MakeGroup(name);
1680 child->MakeNullParameter(100 + i, B_MEDIA_RAW_AUDIO, name,
1681 B_WEB_BUFFER_OUTPUT);
1682
1683 int32 num = 1;
1684 _ProcessGroup(child, i, num);
1685 } else if (controls[i].flags & B_MULTI_MIX_MUX) {
1686 PRINT(("NEW_MUX\n"));
1687 BDiscreteParameter* parameter = group->MakeDiscreteParameter(
1688 100 + i, B_MEDIA_RAW_AUDIO, name, B_INPUT_MUX);
1689 if (numParameters > 0) {
1690 (group->ParameterAt(numParameters - 1))->AddOutput(
1691 group->ParameterAt(numParameters));
1692 numParameters++;
1693 }
1694 _ProcessMux(parameter, i);
1695 } else if (controls[i].flags & B_MULTI_MIX_GAIN) {
1696 PRINT(("NEW_GAIN\n"));
1697 group->MakeContinuousParameter(100 + i,
1698 B_MEDIA_RAW_AUDIO, "", B_MASTER_GAIN, "dB",
1699 controls[i].gain.min_gain, controls[i].gain.max_gain,
1700 controls[i].gain.granularity);
1701
1702 if (i + 1 < fDevice->MixControlInfo().control_count
1703 && controls[i + 1].master == controls[i].id
1704 && (controls[i + 1].flags & B_MULTI_MIX_GAIN) != 0) {
1705 group->ParameterAt(numParameters)->SetChannelCount(
1706 group->ParameterAt(numParameters)->CountChannels() + 1);
1707 i++;
1708 }
1709
1710 PRINT(("num parameters: %" B_PRId32 "\n", numParameters));
1711 if (numParameters > 0) {
1712 group->ParameterAt(numParameters - 1)->AddOutput(
1713 group->ParameterAt(numParameters));
1714 numParameters++;
1715 }
1716 } else if (controls[i].flags & B_MULTI_MIX_ENABLE) {
1717 PRINT(("NEW_ENABLE\n"));
1718 if (controls[i].string == S_MUTE) {
1719 group->MakeDiscreteParameter(100 + i,
1720 B_MEDIA_RAW_AUDIO, name, B_MUTE);
1721 } else {
1722 group->MakeDiscreteParameter(100 + i,
1723 B_MEDIA_RAW_AUDIO, name, B_ENABLE);
1724 }
1725 if (numParameters > 0) {
1726 group->ParameterAt(numParameters - 1)->AddOutput(
1727 group->ParameterAt(numParameters));
1728 numParameters++;
1729 }
1730 }
1731 }
1732 }
1733
1734
1735 void
_ProcessMux(BDiscreteParameter * parameter,int32 index)1736 MultiAudioNode::_ProcessMux(BDiscreteParameter* parameter, int32 index)
1737 {
1738 CALLED();
1739 multi_mix_control* parent = &fDevice->MixControlInfo().controls[index];
1740 multi_mix_control* controls = fDevice->MixControlInfo().controls;
1741 int32 itemIndex = 0;
1742
1743 for (int32 i = 0; i < fDevice->MixControlInfo().control_count; i++) {
1744 if (controls[i].parent != parent->id)
1745 continue;
1746
1747 if ((controls[i].flags & B_MULTI_MIX_MUX_VALUE) != 0) {
1748 PRINT(("NEW_MUX_VALUE\n"));
1749 parameter->AddItem(itemIndex, _GetControlName(controls[i]));
1750 itemIndex++;
1751 }
1752 }
1753 }
1754
1755
1756 void
_CreateFrequencyParameterGroup(BParameterGroup * parentGroup,const char * name,int32 parameterID,uint32 rateMask)1757 MultiAudioNode::_CreateFrequencyParameterGroup(BParameterGroup* parentGroup,
1758 const char* name, int32 parameterID, uint32 rateMask)
1759 {
1760 BParameterGroup* group = parentGroup->MakeGroup(name);
1761 BDiscreteParameter* frequencyParam = group->MakeDiscreteParameter(
1762 parameterID, B_MEDIA_NO_TYPE,
1763 BString(name) << B_TRANSLATE(" frequency:"),
1764 B_GENERIC);
1765
1766 for (int32 i = 0; kSampleRateInfos[i].name != NULL; i++) {
1767 const sample_rate_info& info = kSampleRateInfos[i];
1768 if ((rateMask & info.multiAudioRate) != 0) {
1769 frequencyParam->AddItem(info.multiAudioRate,
1770 BString(info.name) << " Hz");
1771 }
1772 }
1773 }
1774
1775
1776 // #pragma mark - MultiAudioNode specific functions
1777
1778
1779 int32
_OutputThread()1780 MultiAudioNode::_OutputThread()
1781 {
1782 CALLED();
1783 multi_buffer_info bufferInfo;
1784 bufferInfo.info_size = sizeof(multi_buffer_info);
1785 bufferInfo.playback_buffer_cycle = 0;
1786 bufferInfo.record_buffer_cycle = 0;
1787
1788 // init the performance time computation
1789 {
1790 BAutolock locker(fBufferLock);
1791 fTimeComputer.Init(fOutputPreferredFormat.u.raw_audio.frame_rate,
1792 system_time());
1793 }
1794
1795 while (atomic_get(&fQuitThread) == 0) {
1796 BAutolock locker(fBufferLock);
1797 // make sure the buffers don't change while we're playing with them
1798
1799 // send buffer
1800 fDevice->BufferExchange(&bufferInfo);
1801
1802 //PRINT(("MultiAudioNode::RunThread: buffer exchanged\n"));
1803 //PRINT(("MultiAudioNode::RunThread: played_real_time: %lld\n", bufferInfo.played_real_time));
1804 //PRINT(("MultiAudioNode::RunThread: played_frames_count: %lld\n", bufferInfo.played_frames_count));
1805 //PRINT(("MultiAudioNode::RunThread: buffer_cycle: %li\n", bufferInfo.playback_buffer_cycle));
1806
1807 for (int32 i = 0; i < fInputs.CountItems(); i++) {
1808 node_input* input = (node_input*)fInputs.ItemAt(i);
1809
1810 if (bufferInfo.playback_buffer_cycle >= 0
1811 && bufferInfo.playback_buffer_cycle
1812 < fDevice->BufferList().return_playback_buffers
1813 && (input->fOldBufferCycle != bufferInfo.playback_buffer_cycle
1814 || fDevice->BufferList().return_playback_buffers == 1)
1815 && (input->fInput.source != media_source::null
1816 || input->fChannelId == 0)) {
1817 //PRINT(("playback_buffer_cycle ok input: %li %ld\n", i, bufferInfo.playback_buffer_cycle));
1818
1819 input->fBufferCycle = (bufferInfo.playback_buffer_cycle - 1
1820 + fDevice->BufferList().return_playback_buffers)
1821 % fDevice->BufferList().return_playback_buffers;
1822
1823 // update the timesource
1824 if (input->fChannelId == 0) {
1825 //PRINT(("updating timesource\n"));
1826 _UpdateTimeSource(bufferInfo, *input);
1827 }
1828
1829 input->fOldBufferCycle = bufferInfo.playback_buffer_cycle;
1830
1831 if (input->fBuffer != NULL) {
1832 _FillNextBuffer(*input, input->fBuffer);
1833 input->fBuffer->Recycle();
1834 input->fBuffer = NULL;
1835 } else {
1836 // put zeros in current buffer
1837 if (input->fInput.source != media_source::null)
1838 _WriteZeros(*input, input->fBufferCycle);
1839 //PRINT(("MultiAudioNode::Runthread WriteZeros\n"));
1840 }
1841 } else {
1842 //PRINT(("playback_buffer_cycle non ok input: %i\n", i));
1843 }
1844 }
1845
1846 #if 0
1847 PRINT(("MultiAudioNode::RunThread: recorded_real_time: %" B_PRIdBIGTIME
1848 "\n", bufferInfo.recorded_real_time));
1849 PRINT(("MultiAudioNode::RunThread: recorded_frames_count: %"
1850 B_PRId64 "\n", bufferInfo.recorded_frames_count));
1851 PRINT(("MultiAudioNode::RunThread: record_buffer_cycle: %" B_PRIi32
1852 "\n", bufferInfo.record_buffer_cycle));
1853 #endif
1854
1855 for (int32 i = 0; i < fOutputs.CountItems(); i++) {
1856 node_output* output = (node_output*)fOutputs.ItemAt(i);
1857
1858 // make sure we're both started *and* connected before delivering a
1859 // buffer
1860 if (RunState() == BMediaEventLooper::B_STARTED
1861 && output->fOutput.destination != media_destination::null) {
1862 if (bufferInfo.record_buffer_cycle >= 0
1863 && bufferInfo.record_buffer_cycle
1864 < fDevice->BufferList().return_record_buffers
1865 && (output->fOldBufferCycle
1866 != bufferInfo.record_buffer_cycle
1867 || fDevice->BufferList().return_record_buffers == 1)) {
1868 //PRINT(("record_buffer_cycle ok\n"));
1869
1870 output->fBufferCycle = bufferInfo.record_buffer_cycle;
1871
1872 // Get the next buffer of data
1873 BBuffer* buffer = _FillNextBuffer(bufferInfo, *output);
1874 if (buffer != NULL) {
1875 // send the buffer downstream if and only if output is
1876 // enabled
1877 status_t err = B_ERROR;
1878 if (output->fOutputEnabled) {
1879 err = SendBuffer(buffer, output->fOutput.source,
1880 output->fOutput.destination);
1881 }
1882 if (err != B_OK) {
1883 buffer->Recycle();
1884 } else {
1885 // track how much media we've delivered so far
1886 size_t numSamples
1887 = output->fOutput.format.u.raw_audio.buffer_size
1888 / (output->fOutput.format.u.raw_audio.format
1889 & media_raw_audio_format
1890 ::B_AUDIO_SIZE_MASK);
1891 output->fSamplesSent += numSamples;
1892 }
1893 }
1894
1895 output->fOldBufferCycle = bufferInfo.record_buffer_cycle;
1896 } else {
1897 //PRINT(("record_buffer_cycle non ok\n"));
1898 }
1899 }
1900 }
1901 }
1902
1903 return B_OK;
1904 }
1905
1906
1907 void
_WriteZeros(node_input & input,uint32 bufferCycle)1908 MultiAudioNode::_WriteZeros(node_input& input, uint32 bufferCycle)
1909 {
1910 //CALLED();
1911
1912 uint32 channelCount = input.fFormat.u.raw_audio.channel_count;
1913 uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size;
1914 size_t stride = fDevice->BufferList().playback_buffers[bufferCycle]
1915 [input.fChannelId].stride;
1916
1917 switch (input.fFormat.u.raw_audio.format) {
1918 case media_raw_audio_format::B_AUDIO_FLOAT:
1919 for (uint32 channel = 0; channel < channelCount; channel++) {
1920 char* dest = _PlaybackBuffer(bufferCycle,
1921 input.fChannelId + channel);
1922 for (uint32 i = bufferSize; i > 0; i--) {
1923 *(float*)dest = 0;
1924 dest += stride;
1925 }
1926 }
1927 break;
1928
1929 case media_raw_audio_format::B_AUDIO_DOUBLE:
1930 for (uint32 channel = 0; channel < channelCount; channel++) {
1931 char* dest = _PlaybackBuffer(bufferCycle,
1932 input.fChannelId + channel);
1933 for (uint32 i = bufferSize; i > 0; i--) {
1934 *(double*)dest = 0;
1935 dest += stride;
1936 }
1937 }
1938 break;
1939
1940 case media_raw_audio_format::B_AUDIO_INT:
1941 for (uint32 channel = 0; channel < channelCount; channel++) {
1942 char* dest = _PlaybackBuffer(bufferCycle,
1943 input.fChannelId + channel);
1944 for (uint32 i = bufferSize; i > 0; i--) {
1945 *(int32*)dest = 0;
1946 dest += stride;
1947 }
1948 }
1949 break;
1950
1951 case media_raw_audio_format::B_AUDIO_SHORT:
1952 for (uint32 channel = 0; channel < channelCount; channel++) {
1953 char* dest = _PlaybackBuffer(bufferCycle,
1954 input.fChannelId + channel);
1955 for (uint32 i = bufferSize; i > 0; i--) {
1956 *(int16*)dest = 0;
1957 dest += stride;
1958 }
1959 }
1960 break;
1961
1962 case media_raw_audio_format::B_AUDIO_UCHAR:
1963 for (uint32 channel = 0; channel < channelCount; channel++) {
1964 char* dest = _PlaybackBuffer(bufferCycle,
1965 input.fChannelId + channel);
1966 for (uint32 i = bufferSize; i > 0; i--) {
1967 *(uint8*)dest = 128;
1968 dest += stride;
1969 }
1970 }
1971 break;
1972
1973 case media_raw_audio_format::B_AUDIO_CHAR:
1974 for (uint32 channel = 0; channel < channelCount; channel++) {
1975 char* dest = _PlaybackBuffer(bufferCycle,
1976 input.fChannelId + channel);
1977 for (uint32 i = bufferSize; i > 0; i--) {
1978 *(int8*)dest = 0;
1979 dest += stride;
1980 }
1981 }
1982 break;
1983
1984 default:
1985 fprintf(stderr, "ERROR in WriteZeros format not handled\n");
1986 }
1987 }
1988
1989
1990 void
_FillWithZeros(node_input & input)1991 MultiAudioNode::_FillWithZeros(node_input& input)
1992 {
1993 CALLED();
1994 for (int32 i = 0; i < fDevice->BufferList().return_playback_buffers; i++)
1995 _WriteZeros(input, i);
1996 }
1997
1998
1999 void
_FillNextBuffer(node_input & input,BBuffer * buffer)2000 MultiAudioNode::_FillNextBuffer(node_input& input, BBuffer* buffer)
2001 {
2002 uint32 channelCount = input.fInput.format.u.raw_audio.channel_count;
2003 size_t inputSampleSize = input.fInput.format.u.raw_audio.format
2004 & media_raw_audio_format::B_AUDIO_SIZE_MASK;
2005
2006 uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size;
2007
2008 if (buffer->SizeUsed() / inputSampleSize / channelCount != bufferSize) {
2009 fprintf(stderr, "MultiAudioNode: Rejecting buffer: size is different\n");
2010 _WriteZeros(input, input.fBufferCycle);
2011 return;
2012 }
2013
2014 if (channelCount != input.fFormat.u.raw_audio.channel_count) {
2015 fprintf(stderr, "MultiAudioNode: Rejecting buffer: channel count is different\n");
2016 return;
2017 }
2018
2019 if (input.fResampler != NULL) {
2020 size_t srcStride = channelCount * inputSampleSize;
2021
2022 for (uint32 channel = 0; channel < channelCount; channel++) {
2023 char* src = (char*)buffer->Data() + channel * inputSampleSize;
2024 char* dst = _PlaybackBuffer(input.fBufferCycle,
2025 input.fChannelId + channel);
2026 size_t dstStride = _PlaybackStride(input.fBufferCycle,
2027 input.fChannelId + channel);
2028
2029 input.fResampler->Resample(src, srcStride,
2030 dst, dstStride, bufferSize);
2031 }
2032 }
2033 }
2034
2035
2036 status_t
_StartOutputThreadIfNeeded()2037 MultiAudioNode::_StartOutputThreadIfNeeded()
2038 {
2039 CALLED();
2040 // the thread is already started ?
2041 if (fThread >= 0)
2042 return B_OK;
2043
2044 PublishTime(-50, 0, 1.0f);
2045
2046 fThread = spawn_thread(_OutputThreadEntry, "multi_audio audio output",
2047 B_REAL_TIME_PRIORITY, this);
2048 if (fThread < 0)
2049 return fThread;
2050
2051 resume_thread(fThread);
2052 return B_OK;
2053 }
2054
2055
2056 status_t
_StopOutputThread()2057 MultiAudioNode::_StopOutputThread()
2058 {
2059 CALLED();
2060 atomic_set(&fQuitThread, 1);
2061
2062 wait_for_thread(fThread, NULL);
2063 fThread = -1;
2064 return B_OK;
2065 }
2066
2067
2068 void
_AllocateBuffers(node_output & channel)2069 MultiAudioNode::_AllocateBuffers(node_output &channel)
2070 {
2071 CALLED();
2072
2073 // allocate enough buffers to span our downstream latency, plus one
2074 size_t size = channel.fOutput.format.u.raw_audio.buffer_size;
2075 int32 count = int32(fLatency / BufferDuration() + 1 + 1);
2076
2077 PRINT(("\tlatency = %" B_PRIdBIGTIME ", buffer duration = %" B_PRIdBIGTIME
2078 "\n", fLatency, BufferDuration()));
2079 PRINT(("\tcreating group of %" B_PRId32 " buffers, size = %" B_PRIuSIZE
2080 "\n", count, size));
2081 channel.fBufferGroup = new BBufferGroup(size, count);
2082 }
2083
2084
2085 void
_UpdateTimeSource(multi_buffer_info & info,node_input & input)2086 MultiAudioNode::_UpdateTimeSource(multi_buffer_info& info, node_input& input)
2087 {
2088 //CALLED();
2089 if (!fTimeSourceStarted)
2090 return;
2091
2092 // For the first playback buffer, we might get a time of 0 or in the past. Ignore it,
2093 // as otherwise we will wind up with incorrect computations from the TimeComputer.
2094 if (info.played_real_time == 0 || info.played_real_time < fTimeComputer.RealTime())
2095 return;
2096
2097 fTimeComputer.AddTimeStamp(info.played_real_time,
2098 info.played_frames_count);
2099 PublishTime(fTimeComputer.PerformanceTime(), fTimeComputer.RealTime(),
2100 fTimeComputer.Drift());
2101 }
2102
2103
2104 BBuffer*
_FillNextBuffer(multi_buffer_info & info,node_output & output)2105 MultiAudioNode::_FillNextBuffer(multi_buffer_info& info, node_output& output)
2106 {
2107 //CALLED();
2108 // get a buffer from our buffer group
2109 //PRINT(("buffer size: %i, buffer duration: %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration()));
2110 //PRINT(("MBI.record_buffer_cycle: %i\n", MBI.record_buffer_cycle));
2111 //PRINT(("MBI.recorded_real_time: %i\n", MBI.recorded_real_time));
2112 //PRINT(("MBI.recorded_frames_count: %i\n", MBI.recorded_frames_count));
2113 if (output.fBufferGroup == NULL)
2114 return NULL;
2115
2116 BBuffer* buffer = output.fBufferGroup->RequestBuffer(
2117 output.fOutput.format.u.raw_audio.buffer_size, BufferDuration());
2118 if (buffer == NULL) {
2119 // If we fail to get a buffer (for example, if the request times out),
2120 // we skip this buffer and go on to the next, to avoid locking up the
2121 // control thread.
2122 fprintf(stderr, "Buffer is null");
2123 return NULL;
2124 }
2125
2126 if (fDevice == NULL)
2127 fprintf(stderr, "fDevice NULL\n");
2128 if (buffer->Header() == NULL)
2129 fprintf(stderr, "buffer->Header() NULL\n");
2130 if (TimeSource() == NULL)
2131 fprintf(stderr, "TimeSource() NULL\n");
2132
2133 uint32 channelCount = output.fOutput.format.u.raw_audio.channel_count;
2134 size_t outputSampleSize = output.fOutput.format.u.raw_audio.format
2135 & media_raw_audio_format::B_AUDIO_SIZE_MASK;
2136
2137 uint32 bufferSize = fDevice->BufferList().return_record_buffer_size;
2138
2139 if (output.fResampler != NULL) {
2140 size_t dstStride = channelCount * outputSampleSize;
2141
2142 uint32 channelId = output.fChannelId
2143 - fDevice->Description().output_channel_count;
2144
2145 for (uint32 channel = 0; channel < channelCount; channel++) {
2146 char* src = _RecordBuffer(output.fBufferCycle,
2147 channelId + channel);
2148 size_t srcStride = _RecordStride(output.fBufferCycle,
2149 channelId + channel);
2150 char* dst = (char*)buffer->Data() + channel * outputSampleSize;
2151
2152 output.fResampler->Resample(src, srcStride, dst, dstStride,
2153 bufferSize);
2154 }
2155 }
2156
2157 // fill in the buffer header
2158 media_header* header = buffer->Header();
2159 header->type = B_MEDIA_RAW_AUDIO;
2160 header->size_used = output.fOutput.format.u.raw_audio.buffer_size;
2161 header->time_source = TimeSource()->ID();
2162 header->start_time = PerformanceTimeFor(info.recorded_real_time);
2163
2164 return buffer;
2165 }
2166
2167
2168 status_t
GetConfigurationFor(BMessage * message)2169 MultiAudioNode::GetConfigurationFor(BMessage* message)
2170 {
2171 CALLED();
2172 if (message == NULL)
2173 return B_BAD_VALUE;
2174
2175 size_t bufferSize = 128;
2176 void* buffer = malloc(bufferSize);
2177 if (buffer == NULL)
2178 return B_NO_MEMORY;
2179
2180 for (int32 i = 0; i < fWeb->CountParameters(); i++) {
2181 BParameter* parameter = fWeb->ParameterAt(i);
2182 if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER
2183 && parameter->Type() != BParameter::B_DISCRETE_PARAMETER)
2184 continue;
2185
2186 PRINT(("getting parameter %" B_PRIi32 "\n", parameter->ID()));
2187 size_t size = bufferSize;
2188 bigtime_t lastChange;
2189 status_t err;
2190 while ((err = GetParameterValue(parameter->ID(), &lastChange, buffer,
2191 &size)) == B_NO_MEMORY && bufferSize < 128 * 1024) {
2192 bufferSize += 128;
2193 free(buffer);
2194 buffer = malloc(bufferSize);
2195 if (buffer == NULL)
2196 return B_NO_MEMORY;
2197 }
2198
2199 if (err == B_OK && size > 0) {
2200 message->AddInt32("parameterID", parameter->ID());
2201 message->AddData("parameterData", B_RAW_TYPE, buffer, size, false);
2202 } else {
2203 PRINT(("parameter err: %s\n", strerror(err)));
2204 }
2205 }
2206
2207 free(buffer);
2208 PRINT_OBJECT(*message);
2209 return B_OK;
2210 }
2211
2212
2213 node_output*
_FindOutput(media_source source)2214 MultiAudioNode::_FindOutput(media_source source)
2215 {
2216 node_output* channel = NULL;
2217
2218 for (int32 i = 0; i < fOutputs.CountItems(); i++) {
2219 channel = (node_output*)fOutputs.ItemAt(i);
2220 if (source == channel->fOutput.source)
2221 break;
2222 }
2223
2224 if (source != channel->fOutput.source)
2225 return NULL;
2226
2227 return channel;
2228 }
2229
2230
2231 node_input*
_FindInput(media_destination dest)2232 MultiAudioNode::_FindInput(media_destination dest)
2233 {
2234 node_input* channel = NULL;
2235
2236 for (int32 i = 0; i < fInputs.CountItems(); i++) {
2237 channel = (node_input*)fInputs.ItemAt(i);
2238 if (dest == channel->fInput.destination)
2239 break;
2240 }
2241
2242 if (dest != channel->fInput.destination)
2243 return NULL;
2244
2245 return channel;
2246 }
2247
2248
2249 node_input*
_FindInput(int32 destinationId)2250 MultiAudioNode::_FindInput(int32 destinationId)
2251 {
2252 node_input* channel = NULL;
2253
2254 for (int32 i = 0; i < fInputs.CountItems(); i++) {
2255 channel = (node_input*)fInputs.ItemAt(i);
2256 if (destinationId == channel->fInput.destination.id)
2257 break;
2258 }
2259
2260 if (destinationId != channel->fInput.destination.id)
2261 return NULL;
2262
2263 return channel;
2264 }
2265
2266
2267 /*static*/ status_t
_OutputThreadEntry(void * data)2268 MultiAudioNode::_OutputThreadEntry(void* data)
2269 {
2270 CALLED();
2271 return static_cast<MultiAudioNode*>(data)->_OutputThread();
2272 }
2273
2274
2275 status_t
_SetNodeInputFrameRate(float frameRate)2276 MultiAudioNode::_SetNodeInputFrameRate(float frameRate)
2277 {
2278 // check whether the frame rate is supported
2279 uint32 multiAudioRate = MultiAudio::convert_from_sample_rate(frameRate);
2280 if ((fDevice->Description().output_rates & multiAudioRate) == 0)
2281 return B_BAD_VALUE;
2282
2283 BAutolock locker(fBufferLock);
2284
2285 // already set?
2286 if (fDevice->FormatInfo().output.rate == multiAudioRate)
2287 return B_OK;
2288
2289 // set the frame rate on the device
2290 status_t error = fDevice->SetOutputFrameRate(multiAudioRate);
2291 if (error != B_OK)
2292 return error;
2293
2294 if (frameRate <= 0)
2295 return B_BAD_VALUE;
2296
2297 // it went fine -- update all formats
2298 fOutputPreferredFormat.u.raw_audio.frame_rate = frameRate;
2299 fOutputPreferredFormat.u.raw_audio.buffer_size
2300 = fDevice->BufferList().return_playback_buffer_size
2301 * (fOutputPreferredFormat.u.raw_audio.format
2302 & media_raw_audio_format::B_AUDIO_SIZE_MASK)
2303 * fOutputPreferredFormat.u.raw_audio.channel_count;
2304
2305 for (int32 i = 0; node_input* channel = (node_input*)fInputs.ItemAt(i);
2306 i++) {
2307 channel->fPreferredFormat.u.raw_audio.frame_rate = frameRate;
2308 channel->fPreferredFormat.u.raw_audio.buffer_size
2309 = fOutputPreferredFormat.u.raw_audio.buffer_size;
2310
2311 channel->fFormat.u.raw_audio.frame_rate = frameRate;
2312 channel->fFormat.u.raw_audio.buffer_size
2313 = fOutputPreferredFormat.u.raw_audio.buffer_size;
2314
2315 channel->fInput.format.u.raw_audio.frame_rate = frameRate;
2316 channel->fInput.format.u.raw_audio.buffer_size
2317 = fOutputPreferredFormat.u.raw_audio.buffer_size;
2318 }
2319
2320 // make sure the time base is reset
2321 fTimeComputer.SetFrameRate(frameRate);
2322
2323 // update internal latency
2324 _UpdateInternalLatency(fOutputPreferredFormat);
2325
2326 return B_OK;
2327 }
2328
2329
2330 status_t
_SetNodeOutputFrameRate(float frameRate)2331 MultiAudioNode::_SetNodeOutputFrameRate(float frameRate)
2332 {
2333 // check whether the frame rate is supported
2334 uint32 multiAudioRate = MultiAudio::convert_from_sample_rate(frameRate);
2335 if ((fDevice->Description().input_rates & multiAudioRate) == 0)
2336 return B_BAD_VALUE;
2337
2338 BAutolock locker(fBufferLock);
2339
2340 // already set?
2341 if (fDevice->FormatInfo().input.rate == multiAudioRate)
2342 return B_OK;
2343
2344 // set the frame rate on the device
2345 status_t error = fDevice->SetInputFrameRate(multiAudioRate);
2346 if (error != B_OK)
2347 return error;
2348
2349 if (frameRate <= 0
2350 || fInputPreferredFormat.u.raw_audio.channel_count <= 0
2351 || ((fInputPreferredFormat.u.raw_audio.format
2352 & media_raw_audio_format::B_AUDIO_SIZE_MASK) == 0))
2353 return B_BAD_VALUE;
2354
2355 // it went fine -- update all formats
2356 fInputPreferredFormat.u.raw_audio.frame_rate = frameRate;
2357 fInputPreferredFormat.u.raw_audio.buffer_size
2358 = fDevice->BufferList().return_record_buffer_size
2359 * (fInputPreferredFormat.u.raw_audio.format
2360 & media_raw_audio_format::B_AUDIO_SIZE_MASK)
2361 * fInputPreferredFormat.u.raw_audio.channel_count;
2362
2363 for (int32 i = 0; node_output* channel = (node_output*)fOutputs.ItemAt(i);
2364 i++) {
2365 channel->fPreferredFormat.u.raw_audio.frame_rate = frameRate;
2366 channel->fPreferredFormat.u.raw_audio.buffer_size
2367 = fInputPreferredFormat.u.raw_audio.buffer_size;
2368
2369 channel->fOutput.format.u.raw_audio.frame_rate = frameRate;
2370 channel->fOutput.format.u.raw_audio.buffer_size
2371 = fInputPreferredFormat.u.raw_audio.buffer_size;
2372 }
2373
2374 // make sure the time base is reset
2375 fTimeComputer.SetFrameRate(frameRate);
2376
2377 // update internal latency
2378 _UpdateInternalLatency(fInputPreferredFormat);
2379
2380 return B_OK;
2381 }
2382
2383
2384 void
_UpdateInternalLatency(const media_format & format)2385 MultiAudioNode::_UpdateInternalLatency(const media_format& format)
2386 {
2387 // use half a buffer length latency
2388 fInternalLatency = format.u.raw_audio.buffer_size * 10000 / 2
2389 / ((format.u.raw_audio.format
2390 & media_raw_audio_format::B_AUDIO_SIZE_MASK)
2391 * format.u.raw_audio.channel_count)
2392 / ((int32)(format.u.raw_audio.frame_rate / 100));
2393
2394 PRINT((" internal latency = %" B_PRIdBIGTIME "\n", fInternalLatency));
2395
2396 SetEventLatency(fInternalLatency);
2397 }
2398