1 /* 2 * multiaudio replacement media addon for BeOS 3 * 4 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) 5 * 6 * All rights reserved. 7 * Redistribution and use in source and binary forms, with or without modification, 8 * are permitted provided that the following conditions are met: 9 * 10 * - Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 25 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 */ 28 #include <MediaDefs.h> 29 #include <MediaNode.h> 30 #include <MediaAddOn.h> 31 #include <BufferConsumer.h> 32 #include <FileInterface.h> 33 #include <Controllable.h> 34 #include <MediaEventLooper.h> 35 #include <File.h> 36 #include <Errors.h> 37 #include <Entry.h> 38 #include <BufferGroup.h> 39 #include <TimeSource.h> 40 #include <Buffer.h> 41 #include <ParameterWeb.h> 42 #include <MediaRoster.h> 43 #include <limits.h> 44 #include <MediaDefs.h> 45 #include <Message.h> 46 47 #include "MultiAudioNode.h" 48 #include "driver_io.h" 49 #ifdef DEBUG 50 #define PRINTING 51 #endif 52 #include "debug.h" 53 54 #include <stdio.h> 55 #include <string.h> 56 57 const char * multi_string[] = 58 { 59 "NAME IS ATTACHED", 60 "Output", "Input", "Setup", "Tone Control", "Extended Setup", "Enhanced Setup", "Master", 61 "Beep", "Phone", "Mic", "Line", "CD", "Video", "Aux", "Wave", "Gain", "Level", "Volume", 62 "Mute", "Enable", "Stereo Mix", "Mono Mix", "Output Stereo Mix", "Output Mono Mix", "Output Bass", 63 "Output Treble", "Output 3D Center", "Output 3D Depth" 64 }; 65 66 node_input::node_input(media_input &input, media_format format) 67 { 68 CALLED(); 69 fInput = input; 70 fPreferredFormat = format; 71 fBufferCycle = 1; 72 fBuffer = NULL; 73 } 74 75 node_input::~node_input() 76 { 77 CALLED(); 78 } 79 80 node_output::node_output(media_output &output, media_format format) 81 : fBufferGroup(NULL), 82 fOutputEnabled(true) 83 { 84 CALLED(); 85 fOutput = output; 86 fPreferredFormat = format; 87 fBufferCycle = 1; 88 } 89 90 node_output::~node_output() 91 { 92 CALLED(); 93 } 94 95 96 // -------------------------------------------------------- // 97 // ctor/dtor 98 // -------------------------------------------------------- // 99 100 MultiAudioNode::~MultiAudioNode(void) 101 { 102 CALLED(); 103 fAddOn->GetConfigurationFor(this, NULL); 104 105 StopThread(); 106 BMediaEventLooper::Quit(); 107 108 fWeb = NULL; 109 } 110 111 MultiAudioNode::MultiAudioNode(BMediaAddOn *addon, char* name, MultiAudioDevice *device, 112 int32 internal_id, BMessage * config) 113 : BMediaNode(name), 114 BBufferConsumer(B_MEDIA_RAW_AUDIO), 115 BBufferProducer(B_MEDIA_RAW_AUDIO), 116 BTimeSource(), 117 BMediaEventLooper(), 118 fThread(-1), 119 fDevice(device), 120 fTimeSourceStarted(false), 121 fWeb(NULL), 122 fConfig(*config) 123 { 124 CALLED(); 125 fInitCheckStatus = B_NO_INIT; 126 127 if(!device) 128 return; 129 130 fAddOn = addon; 131 fId = internal_id; 132 133 AddNodeKind( B_PHYSICAL_OUTPUT ); 134 AddNodeKind( B_PHYSICAL_INPUT ); 135 136 // initialize our preferred format object 137 memset(&fPreferredFormat, 0, sizeof(fPreferredFormat)); // set everything to wildcard first 138 fPreferredFormat.type = B_MEDIA_RAW_AUDIO; 139 fPreferredFormat.u.raw_audio.format = MultiAudioDevice::convert_multiaudio_format_to_media_format(fDevice->MFI.output.format); 140 fPreferredFormat.u.raw_audio.valid_bits = MultiAudioDevice::convert_multiaudio_format_to_valid_bits(fDevice->MFI.output.format); 141 fPreferredFormat.u.raw_audio.channel_count = 2; 142 fPreferredFormat.u.raw_audio.frame_rate = MultiAudioDevice::convert_multiaudio_rate_to_media_rate(fDevice->MFI.input.rate); // measured in Hertz 143 fPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 144 145 // we'll use the consumer's preferred buffer size, if any 146 fPreferredFormat.u.raw_audio.buffer_size = fDevice->MBL.return_record_buffer_size 147 * (fPreferredFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 148 * fPreferredFormat.u.raw_audio.channel_count; 149 150 if(config) { 151 PRINT_OBJECT(*config); 152 } 153 154 fInitCheckStatus = B_OK; 155 } 156 157 status_t MultiAudioNode::InitCheck(void) const 158 { 159 CALLED(); 160 return fInitCheckStatus; 161 } 162 163 164 // -------------------------------------------------------- // 165 // implementation of BMediaNode 166 // -------------------------------------------------------- // 167 168 BMediaAddOn * MultiAudioNode::AddOn( 169 int32 * internal_id) const 170 { 171 CALLED(); 172 // BeBook says this only gets called if we were in an add-on. 173 if (fAddOn != 0) { 174 // If we get a null pointer then we just won't write. 175 if (internal_id != 0) { 176 *internal_id = fId; 177 } 178 } 179 return fAddOn; 180 } 181 182 void MultiAudioNode::Preroll(void) 183 { 184 CALLED(); 185 // XXX:Performance opportunity 186 BMediaNode::Preroll(); 187 } 188 189 status_t MultiAudioNode::HandleMessage( 190 int32 message, 191 const void * data, 192 size_t size) 193 { 194 CALLED(); 195 return B_ERROR; 196 } 197 198 void MultiAudioNode::NodeRegistered(void) 199 { 200 CALLED(); 201 202 if (fInitCheckStatus != B_OK) { 203 ReportError(B_NODE_IN_DISTRESS); 204 return; 205 } 206 207 SetPriority(B_REAL_TIME_PRIORITY); 208 209 Run(); 210 211 node_input *currentInput = NULL; 212 int32 currentId = 0; 213 214 for (int32 i = 0; i < fDevice->MD.output_channel_count; i++) { 215 216 if( (currentInput == NULL) 217 || (fDevice->MD.channels[i].designations & B_CHANNEL_MONO_BUS) 218 || (fDevice->MD.channels[currentId].designations & B_CHANNEL_STEREO_BUS 219 && ( fDevice->MD.channels[i].designations & B_CHANNEL_LEFT || 220 !(fDevice->MD.channels[i].designations & B_CHANNEL_STEREO_BUS))) 221 || (fDevice->MD.channels[currentId].designations & B_CHANNEL_SURROUND_BUS 222 && ( fDevice->MD.channels[i].designations & B_CHANNEL_LEFT || 223 !(fDevice->MD.channels[i].designations & B_CHANNEL_SURROUND_BUS))) 224 ) { 225 PRINT(("NodeRegistered() : creating an input for %i\n", i)); 226 PRINT(("%ld\t%d\t0x%lx\t0x%lx\n",fDevice->MD.channels[i].channel_id, 227 fDevice->MD.channels[i].kind, 228 fDevice->MD.channels[i].designations, 229 fDevice->MD.channels[i].connectors)); 230 231 media_input *input = new media_input; 232 233 input->format = fPreferredFormat; 234 input->destination.port = ControlPort(); 235 input->destination.id = fInputs.CountItems(); 236 input->node = Node(); 237 sprintf(input->name, "output %ld", input->destination.id); 238 239 currentInput = new node_input(*input, fPreferredFormat); 240 currentInput->fPreferredFormat.u.raw_audio.channel_count = 1; 241 currentInput->fInput.format = currentInput->fPreferredFormat; 242 243 currentInput->fChannelId = fDevice->MD.channels[i].channel_id; 244 fInputs.AddItem(currentInput); 245 246 currentId = i; 247 248 } else { 249 PRINT(("NodeRegistered() : adding a channel\n")); 250 currentInput->fPreferredFormat.u.raw_audio.channel_count++; 251 currentInput->fInput.format = currentInput->fPreferredFormat; 252 } 253 currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format; 254 } 255 256 node_output *currentOutput = NULL; 257 currentId = 0; 258 259 for (int32 i = fDevice->MD.output_channel_count; 260 i < (fDevice->MD.output_channel_count + fDevice->MD.input_channel_count); i++) { 261 262 if( (currentOutput == NULL) 263 || (fDevice->MD.channels[i].designations & B_CHANNEL_MONO_BUS) 264 || (fDevice->MD.channels[currentId].designations & B_CHANNEL_STEREO_BUS 265 && ( fDevice->MD.channels[i].designations & B_CHANNEL_LEFT || 266 !(fDevice->MD.channels[i].designations & B_CHANNEL_STEREO_BUS))) 267 || (fDevice->MD.channels[currentId].designations & B_CHANNEL_SURROUND_BUS 268 && ( fDevice->MD.channels[i].designations & B_CHANNEL_LEFT || 269 !(fDevice->MD.channels[i].designations & B_CHANNEL_SURROUND_BUS))) 270 ) { 271 PRINT(("NodeRegistered() : creating an output for %i\n", i)); 272 PRINT(("%ld\t%d\t0x%lx\t0x%lx\n",fDevice->MD.channels[i].channel_id, 273 fDevice->MD.channels[i].kind, 274 fDevice->MD.channels[i].designations, 275 fDevice->MD.channels[i].connectors)); 276 277 media_output *output = new media_output; 278 279 output->format = fPreferredFormat; 280 output->destination = media_destination::null; 281 output->source.port = ControlPort(); 282 output->source.id = fOutputs.CountItems(); 283 output->node = Node(); 284 sprintf(output->name, "input %ld", output->source.id); 285 286 currentOutput = new node_output(*output, fPreferredFormat); 287 currentOutput->fPreferredFormat.u.raw_audio.channel_count = 1; 288 currentOutput->fOutput.format = currentOutput->fPreferredFormat; 289 currentOutput->fChannelId = fDevice->MD.channels[i].channel_id; 290 fOutputs.AddItem(currentOutput); 291 292 currentId = i; 293 294 } else { 295 PRINT(("NodeRegistered() : adding a channel\n")); 296 currentOutput->fPreferredFormat.u.raw_audio.channel_count++; 297 currentOutput->fOutput.format = currentOutput->fPreferredFormat; 298 } 299 } 300 301 // Set up our parameter web 302 fWeb = MakeParameterWeb(); 303 SetParameterWeb(fWeb); 304 305 /* apply configuration */ 306 #ifdef PRINTING 307 bigtime_t start = system_time(); 308 #endif 309 310 int32 index = 0; 311 int32 parameterID = 0; 312 const void *data; 313 ssize_t size; 314 while(fConfig.FindInt32("parameterID", index, ¶meterID) == B_OK) { 315 if(fConfig.FindData("parameterData", B_RAW_TYPE, index, &data, &size) == B_OK) 316 SetParameterValue(parameterID, TimeSource()->Now(), data, size); 317 index++; 318 } 319 320 PRINT(("apply configuration in : %ld\n", system_time() - start)); 321 } 322 323 status_t MultiAudioNode::RequestCompleted(const media_request_info &info) 324 { 325 CALLED(); 326 return B_OK; 327 } 328 329 void MultiAudioNode::SetTimeSource(BTimeSource *timeSource) 330 { 331 CALLED(); 332 } 333 334 // -------------------------------------------------------- // 335 // implemention of BBufferConsumer 336 // -------------------------------------------------------- // 337 338 // Check to make sure the format is okay, then remove 339 // any wildcards corresponding to our requirements. 340 status_t MultiAudioNode::AcceptFormat( 341 const media_destination & dest, 342 media_format * format) 343 { 344 CALLED(); 345 346 node_input *channel = FindInput(dest); 347 348 if(channel==NULL) { 349 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION"); 350 return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it 351 } 352 353 if (format == 0) { 354 fprintf(stderr,"<- B_BAD_VALUE\n"); 355 return B_BAD_VALUE; // no crashing 356 } 357 /* media_format * myFormat = GetFormat(); 358 fprintf(stderr,"proposed format: "); 359 print_media_format(format); 360 fprintf(stderr,"\n"); 361 fprintf(stderr,"my format: "); 362 print_media_format(myFormat); 363 fprintf(stderr,"\n");*/ 364 // Be's format_is_compatible doesn't work. 365 // if (!format_is_compatible(*format,*myFormat)) { 366 367 if ( format->type != B_MEDIA_RAW_AUDIO ) { 368 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 369 return B_MEDIA_BAD_FORMAT; 370 } 371 372 channel->fFormat = channel->fPreferredFormat; 373 374 /*if(format->u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT 375 && channel->fPreferredFormat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) 376 format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; 377 else*/ 378 format->u.raw_audio.format = channel->fPreferredFormat.u.raw_audio.format; 379 format->u.raw_audio.valid_bits = channel->fPreferredFormat.u.raw_audio.valid_bits; 380 381 format->u.raw_audio.frame_rate = channel->fPreferredFormat.u.raw_audio.frame_rate; 382 format->u.raw_audio.channel_count = channel->fPreferredFormat.u.raw_audio.channel_count; 383 format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 384 format->u.raw_audio.buffer_size = fDevice->MBL.return_playback_buffer_size 385 * (format->u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 386 * format->u.raw_audio.channel_count; 387 388 389 /*media_format myFormat; 390 GetFormat(&myFormat); 391 if (!format_is_acceptible(*format,myFormat)) { 392 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 393 return B_MEDIA_BAD_FORMAT; 394 }*/ 395 //AddRequirements(format); 396 return B_OK; 397 } 398 399 status_t MultiAudioNode::GetNextInput( 400 int32 * cookie, 401 media_input * out_input) 402 { 403 CALLED(); 404 // let's not crash even if they are stupid 405 if (out_input == 0) { 406 // no place to write! 407 fprintf(stderr,"<- B_BAD_VALUE\n"); 408 return B_BAD_VALUE; 409 } 410 411 if ((*cookie < fInputs.CountItems()) && (*cookie >= 0)) { 412 node_input *channel = (node_input *)fInputs.ItemAt(*cookie); 413 *out_input = channel->fInput; 414 *cookie += 1; 415 PRINT(("input.format : %u\n", channel->fInput.format.u.raw_audio.format)); 416 return B_OK; 417 } else 418 return B_BAD_INDEX; 419 } 420 421 void MultiAudioNode::DisposeInputCookie( 422 int32 cookie) 423 { 424 CALLED(); 425 // nothing to do since our cookies are just integers 426 } 427 428 void MultiAudioNode::BufferReceived( 429 BBuffer * buffer) 430 { 431 //CALLED(); 432 switch (buffer->Header()->type) { 433 /*case B_MEDIA_PARAMETERS: 434 { 435 status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed()); 436 if (status != B_OK) { 437 fprintf(stderr,"ApplyParameterData in MultiAudioNode::BufferReceived failed\n"); 438 } 439 buffer->Recycle(); 440 } 441 break;*/ 442 case B_MEDIA_RAW_AUDIO: 443 if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) { 444 fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MultiAudioNode::BufferReceived\n"); 445 // XXX: implement this part 446 buffer->Recycle(); 447 } else { 448 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 449 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 450 status_t status = EventQueue()->AddEvent(event); 451 if (status != B_OK) { 452 fprintf(stderr,"EventQueue()->AddEvent(event) in MultiAudioNode::BufferReceived failed\n"); 453 buffer->Recycle(); 454 } 455 } 456 break; 457 default: 458 fprintf(stderr,"unexpected buffer type in MultiAudioNode::BufferReceived\n"); 459 buffer->Recycle(); 460 break; 461 } 462 } 463 464 void MultiAudioNode::ProducerDataStatus( 465 const media_destination & for_whom, 466 int32 status, 467 bigtime_t at_performance_time) 468 { 469 //CALLED(); 470 471 node_input *channel = FindInput(for_whom); 472 473 if(channel==NULL) { 474 fprintf(stderr,"invalid destination received in MultiAudioNode::ProducerDataStatus\n"); 475 return; 476 } 477 478 media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, 479 &channel->fInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 480 EventQueue()->AddEvent(event); 481 } 482 483 status_t MultiAudioNode::GetLatencyFor( 484 const media_destination & for_whom, 485 bigtime_t * out_latency, 486 media_node_id * out_timesource) 487 { 488 CALLED(); 489 if ((out_latency == 0) || (out_timesource == 0)) { 490 fprintf(stderr,"<- B_BAD_VALUE\n"); 491 return B_BAD_VALUE; 492 } 493 494 node_input *channel = FindInput(for_whom); 495 496 if(channel==NULL) { 497 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 498 return B_MEDIA_BAD_DESTINATION; 499 } 500 *out_latency = EventLatency(); 501 *out_timesource = TimeSource()->ID(); 502 return B_OK; 503 } 504 505 status_t MultiAudioNode::Connected( 506 const media_source & producer, /* here's a good place to request buffer group usage */ 507 const media_destination & where, 508 const media_format & with_format, 509 media_input * out_input) 510 { 511 CALLED(); 512 if (out_input == 0) { 513 fprintf(stderr,"<- B_BAD_VALUE\n"); 514 return B_BAD_VALUE; // no crashing 515 } 516 517 node_input *channel = FindInput(where); 518 519 if(channel==NULL) { 520 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 521 return B_MEDIA_BAD_DESTINATION; 522 } 523 524 // use one buffer length latency 525 fInternalLatency = with_format.u.raw_audio.buffer_size * 10000 / 2 526 / ( (with_format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 527 * with_format.u.raw_audio.channel_count) 528 / ((int32)(with_format.u.raw_audio.frame_rate / 100)); 529 530 PRINT((" internal latency = %lld\n",fInternalLatency)); 531 532 SetEventLatency(fInternalLatency); 533 534 // record the agreed upon values 535 channel->fInput.source = producer; 536 channel->fInput.format = with_format; 537 *out_input = channel->fInput; 538 539 // we are sure the thread is started 540 StartThread(); 541 542 return B_OK; 543 } 544 545 void MultiAudioNode::Disconnected( 546 const media_source & producer, 547 const media_destination & where) 548 { 549 CALLED(); 550 node_input *channel = FindInput(where); 551 552 if(channel==NULL) { 553 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 554 return; 555 } 556 if (channel->fInput.source != producer) { 557 fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n"); 558 return; 559 } 560 561 channel->fInput.source = media_source::null; 562 channel->fInput.format = channel->fPreferredFormat; 563 FillWithZeros(*channel); 564 //GetFormat(&channel->fInput.format); 565 } 566 567 /* The notification comes from the upstream producer, so he's already cool with */ 568 /* the format; you should not ask him about it in here. */ 569 status_t MultiAudioNode::FormatChanged( 570 const media_source & producer, 571 const media_destination & consumer, 572 int32 change_tag, 573 const media_format & format) 574 { 575 CALLED(); 576 node_input *channel = FindInput(consumer); 577 578 if(channel==NULL) { 579 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 580 return B_MEDIA_BAD_DESTINATION; 581 } 582 if (channel->fInput.source != producer) { 583 return B_MEDIA_BAD_SOURCE; 584 } 585 586 return B_ERROR; 587 } 588 589 /* Given a performance time of some previous buffer, retrieve the remembered tag */ 590 /* of the closest (previous or exact) performance time. Set *out_flags to 0; the */ 591 /* idea being that flags can be added later, and the understood flags returned in */ 592 /* *out_flags. */ 593 status_t MultiAudioNode::SeekTagRequested( 594 const media_destination & destination, 595 bigtime_t in_target_time, 596 uint32 in_flags, 597 media_seek_tag * out_seek_tag, 598 bigtime_t * out_tagged_time, 599 uint32 * out_flags) 600 { 601 CALLED(); 602 return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags, 603 out_seek_tag,out_tagged_time,out_flags); 604 } 605 606 // -------------------------------------------------------- // 607 // implementation for BBufferProducer 608 // -------------------------------------------------------- // 609 610 status_t 611 MultiAudioNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, media_format* format) 612 { 613 // FormatSuggestionRequested() is not necessarily part of the format negotiation 614 // process; it's simply an interrogation -- the caller wants to see what the node's 615 // preferred data format is, given a suggestion by the caller. 616 CALLED(); 617 618 if (!format) 619 { 620 fprintf(stderr, "\tERROR - NULL format pointer passed in!\n"); 621 return B_BAD_VALUE; 622 } 623 624 // this is the format we'll be returning (our preferred format) 625 *format = fPreferredFormat; 626 627 // a wildcard type is okay; we can specialize it 628 if (type == B_MEDIA_UNKNOWN_TYPE) type = B_MEDIA_RAW_AUDIO; 629 630 // we only support raw audio 631 if (type != B_MEDIA_RAW_AUDIO) return B_MEDIA_BAD_FORMAT; 632 else return B_OK; 633 } 634 635 status_t 636 MultiAudioNode::FormatProposal(const media_source& output, media_format* format) 637 { 638 // FormatProposal() is the first stage in the BMediaRoster::Connect() process. We hand 639 // out a suggested format, with wildcards for any variations we support. 640 CALLED(); 641 node_output *channel = FindOutput(output); 642 643 // is this a proposal for our select output? 644 if (channel == NULL) 645 { 646 fprintf(stderr, "MultiAudioNode::FormatProposal returning B_MEDIA_BAD_SOURCE\n"); 647 return B_MEDIA_BAD_SOURCE; 648 } 649 650 // we only support floating-point raw audio, so we always return that, but we 651 // supply an error code depending on whether we found the proposal acceptable. 652 media_type requestedType = format->type; 653 *format = channel->fPreferredFormat; 654 if ((requestedType != B_MEDIA_UNKNOWN_TYPE) && (requestedType != B_MEDIA_RAW_AUDIO)) 655 { 656 fprintf(stderr, "MultiAudioNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n"); 657 return B_MEDIA_BAD_FORMAT; 658 } 659 else return B_OK; // raw audio or wildcard type, either is okay by us 660 } 661 662 status_t 663 MultiAudioNode::FormatChangeRequested(const media_source& source, const media_destination& destination, media_format* io_format, int32* _deprecated_) 664 { 665 CALLED(); 666 667 // we don't support any other formats, so we just reject any format changes. 668 return B_ERROR; 669 } 670 671 status_t 672 MultiAudioNode::GetNextOutput(int32* cookie, media_output* out_output) 673 { 674 CALLED(); 675 676 if ((*cookie < fOutputs.CountItems()) && (*cookie >= 0)) { 677 node_output *channel = (node_output *)fOutputs.ItemAt(*cookie); 678 *out_output = channel->fOutput; 679 *cookie += 1; 680 return B_OK; 681 } else 682 return B_BAD_INDEX; 683 } 684 685 status_t 686 MultiAudioNode::DisposeOutputCookie(int32 cookie) 687 { 688 CALLED(); 689 // do nothing because we don't use the cookie for anything special 690 return B_OK; 691 } 692 693 status_t 694 MultiAudioNode::SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup) 695 { 696 CALLED(); 697 698 node_output *channel = FindOutput(for_source); 699 700 // is this our output? 701 if (channel == NULL) 702 { 703 fprintf(stderr, "MultiAudioNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n"); 704 return B_MEDIA_BAD_SOURCE; 705 } 706 707 // Are we being passed the buffer group we're already using? 708 if (newGroup == channel->fBufferGroup) return B_OK; 709 710 // Ahh, someone wants us to use a different buffer group. At this point we delete 711 // the one we are using and use the specified one instead. If the specified group is 712 // NULL, we need to recreate one ourselves, and use *that*. Note that if we're 713 // caching a BBuffer that we requested earlier, we have to Recycle() that buffer 714 // *before* deleting the buffer group, otherwise we'll deadlock waiting for that 715 // buffer to be recycled! 716 delete channel->fBufferGroup; // waits for all buffers to recycle 717 if (newGroup != NULL) 718 { 719 // we were given a valid group; just use that one from now on 720 channel->fBufferGroup = newGroup; 721 } 722 else 723 { 724 // we were passed a NULL group pointer; that means we construct 725 // our own buffer group to use from now on 726 size_t size = channel->fOutput.format.u.raw_audio.buffer_size; 727 int32 count = int32(fLatency / BufferDuration() + 1 + 1); 728 channel->fBufferGroup = new BBufferGroup(size, count); 729 } 730 731 return B_OK; 732 } 733 734 status_t 735 MultiAudioNode::PrepareToConnect(const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name) 736 { 737 // PrepareToConnect() is the second stage of format negotiations that happens 738 // inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat() 739 // method has been called, and that node has potentially changed the proposed 740 // format. It may also have left wildcards in the format. PrepareToConnect() 741 // *must* fully specialize the format before returning! 742 CALLED(); 743 744 node_output *channel = FindOutput(what); 745 746 // is this our output? 747 if (channel == NULL) 748 { 749 fprintf(stderr, "MultiAudioNode::PrepareToConnect returning B_MEDIA_BAD_SOURCE\n"); 750 return B_MEDIA_BAD_SOURCE; 751 } 752 753 // are we already connected? 754 if (channel->fOutput.destination != media_destination::null) 755 return B_MEDIA_ALREADY_CONNECTED; 756 757 // the format may not yet be fully specialized (the consumer might have 758 // passed back some wildcards). Finish specializing it now, and return an 759 // error if we don't support the requested format. 760 if (format->type != B_MEDIA_RAW_AUDIO) 761 { 762 fprintf(stderr, "\tnon-raw-audio format?!\n"); 763 return B_MEDIA_BAD_FORMAT; 764 } 765 766 // !!! validate all other fields except for buffer_size here, because the consumer might have 767 // supplied different values from AcceptFormat()? 768 769 // check the buffer size, which may still be wildcarded 770 if (format->u.raw_audio.buffer_size == media_raw_audio_format::wildcard.buffer_size) 771 { 772 format->u.raw_audio.buffer_size = 2048; // pick something comfortable to suggest 773 fprintf(stderr, "\tno buffer size provided, suggesting %lu\n", format->u.raw_audio.buffer_size); 774 } 775 else 776 { 777 fprintf(stderr, "\tconsumer suggested buffer_size %lu\n", format->u.raw_audio.buffer_size); 778 } 779 780 // Now reserve the connection, and return information about it 781 channel->fOutput.destination = where; 782 channel->fOutput.format = *format; 783 *out_source = channel->fOutput.source; 784 strncpy(out_name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); 785 return B_OK; 786 } 787 788 void 789 MultiAudioNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) 790 { 791 CALLED(); 792 793 node_output *channel = FindOutput(source); 794 795 // is this our output? 796 if (channel == NULL) 797 { 798 fprintf(stderr, "MultiAudioNode::Connect returning (cause : B_MEDIA_BAD_SOURCE)\n"); 799 return; 800 } 801 802 // If something earlier failed, Connect() might still be called, but with a non-zero 803 // error code. When that happens we simply unreserve the connection and do 804 // nothing else. 805 if (error) 806 { 807 channel->fOutput.destination = media_destination::null; 808 channel->fOutput.format = channel->fPreferredFormat; 809 return; 810 } 811 812 // Okay, the connection has been confirmed. Record the destination and format 813 // that we agreed on, and report our connection name again. 814 channel->fOutput.destination = destination; 815 channel->fOutput.format = format; 816 strncpy(io_name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); 817 818 // reset our buffer duration, etc. to avoid later calculations 819 bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000 820 / ( (channel->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 821 * channel->fOutput.format.u.raw_audio.channel_count) 822 / ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100)); 823 824 SetBufferDuration(duration); 825 826 // Now that we're connected, we can determine our downstream latency. 827 // Do so, then make sure we get our events early enough. 828 media_node_id id; 829 FindLatencyFor(channel->fOutput.destination, &fLatency, &id); 830 PRINT(("\tdownstream latency = %Ld\n", fLatency)); 831 832 fInternalLatency = BufferDuration(); 833 PRINT(("\tbuffer-filling took %Ld usec on this machine\n", fInternalLatency)); 834 //SetEventLatency(fLatency + fInternalLatency); 835 836 // Set up the buffer group for our connection, as long as nobody handed us a 837 // buffer group (via SetBufferGroup()) prior to this. That can happen, for example, 838 // if the consumer calls SetOutputBuffersFor() on us from within its Connected() 839 // method. 840 if (!channel->fBufferGroup) 841 AllocateBuffers(*channel); 842 843 // we are sure the thread is started 844 StartThread(); 845 } 846 847 void 848 MultiAudioNode::Disconnect(const media_source& what, const media_destination& where) 849 { 850 CALLED(); 851 852 node_output *channel = FindOutput(what); 853 854 // is this our output? 855 if (channel == NULL) 856 { 857 fprintf(stderr, "MultiAudioNode::Disconnect() returning (cause : B_MEDIA_BAD_SOURCE)\n"); 858 return; 859 } 860 861 // Make sure that our connection is the one being disconnected 862 if ((where == channel->fOutput.destination) && (what == channel->fOutput.source)) 863 { 864 channel->fOutput.destination = media_destination::null; 865 channel->fOutput.format = channel->fPreferredFormat; 866 delete channel->fBufferGroup; 867 channel->fBufferGroup = NULL; 868 } 869 else 870 { 871 fprintf(stderr, "\tDisconnect() called with wrong source/destination (%ld/%ld), ours is (%ld/%ld)\n", 872 what.id, where.id, channel->fOutput.source.id, channel->fOutput.destination.id); 873 } 874 } 875 876 void 877 MultiAudioNode::LateNoticeReceived(const media_source& what, bigtime_t how_much, bigtime_t performance_time) 878 { 879 CALLED(); 880 881 node_output *channel = FindOutput(what); 882 883 // is this our output? 884 if (channel == NULL) 885 { 886 return; 887 } 888 889 // If we're late, we need to catch up. Respond in a manner appropriate to our 890 // current run mode. 891 if (RunMode() == B_RECORDING) 892 { 893 // A hardware capture node can't adjust; it simply emits buffers at 894 // appropriate points. We (partially) simulate this by not adjusting 895 // our behavior upon receiving late notices -- after all, the hardware 896 // can't choose to capture "sooner".... 897 } 898 else if (RunMode() == B_INCREASE_LATENCY) 899 { 900 // We're late, and our run mode dictates that we try to produce buffers 901 // earlier in order to catch up. This argues that the downstream nodes are 902 // not properly reporting their latency, but there's not much we can do about 903 // that at the moment, so we try to start producing buffers earlier to 904 // compensate. 905 fInternalLatency += how_much; 906 SetEventLatency(fLatency + fInternalLatency); 907 908 fprintf(stderr, "\tincreasing latency to %Ld\n", fLatency + fInternalLatency); 909 } 910 else 911 { 912 // The other run modes dictate various strategies for sacrificing data quality 913 // in the interests of timely data delivery. The way *we* do this is to skip 914 // a buffer, which catches us up in time by one buffer duration. 915 /*size_t nSamples = fOutput.format.u.raw_audio.buffer_size / sizeof(float); 916 mSamplesSent += nSamples;*/ 917 918 fprintf(stderr, "\tskipping a buffer to try to catch up\n"); 919 } 920 } 921 922 void 923 MultiAudioNode::EnableOutput(const media_source& what, bool enabled, int32* _deprecated_) 924 { 925 CALLED(); 926 927 // If I had more than one output, I'd have to walk my list of output records to see 928 // which one matched the given source, and then enable/disable that one. But this 929 // node only has one output, so I just make sure the given source matches, then set 930 // the enable state accordingly. 931 node_output *channel = FindOutput(what); 932 933 if (channel != NULL) 934 { 935 channel->fOutputEnabled = enabled; 936 } 937 } 938 939 void 940 MultiAudioNode::AdditionalBufferRequested(const media_source& source, media_buffer_id prev_buffer, bigtime_t prev_time, const media_seek_tag* prev_tag) 941 { 942 CALLED(); 943 // we don't support offline mode 944 return; 945 } 946 947 // -------------------------------------------------------- // 948 // implementation for BMediaEventLooper 949 // -------------------------------------------------------- // 950 951 void MultiAudioNode::HandleEvent( 952 const media_timed_event *event, 953 bigtime_t lateness, 954 bool realTimeEvent) 955 { 956 //CALLED(); 957 switch (event->type) { 958 case BTimedEventQueue::B_START: 959 HandleStart(event,lateness,realTimeEvent); 960 break; 961 case BTimedEventQueue::B_SEEK: 962 HandleSeek(event,lateness,realTimeEvent); 963 break; 964 case BTimedEventQueue::B_WARP: 965 HandleWarp(event,lateness,realTimeEvent); 966 break; 967 case BTimedEventQueue::B_STOP: 968 HandleStop(event,lateness,realTimeEvent); 969 break; 970 case BTimedEventQueue::B_HANDLE_BUFFER: 971 if (RunState() == BMediaEventLooper::B_STARTED) { 972 HandleBuffer(event,lateness,realTimeEvent); 973 } 974 break; 975 case BTimedEventQueue::B_DATA_STATUS: 976 HandleDataStatus(event,lateness,realTimeEvent); 977 break; 978 case BTimedEventQueue::B_PARAMETER: 979 HandleParameter(event,lateness,realTimeEvent); 980 break; 981 default: 982 fprintf(stderr," unknown event type: %li\n",event->type); 983 break; 984 } 985 } 986 987 // protected: 988 989 // how should we handle late buffers? drop them? 990 // notify the producer? 991 status_t MultiAudioNode::HandleBuffer( 992 const media_timed_event *event, 993 bigtime_t lateness, 994 bool realTimeEvent) 995 { 996 //CALLED(); 997 BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer); 998 if (buffer == 0) { 999 fprintf(stderr,"<- B_BAD_VALUE\n"); 1000 return B_BAD_VALUE; 1001 } 1002 1003 node_input *channel = FindInput(buffer->Header()->destination); 1004 //PRINT(("buffer->Header()->destination : %i\n", buffer->Header()->destination)); 1005 1006 if(channel==NULL) { 1007 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 1008 return B_MEDIA_BAD_DESTINATION; 1009 } 1010 1011 media_header* hdr = buffer->Header(); 1012 bigtime_t now = TimeSource()->Now(); 1013 bigtime_t perf_time = hdr->start_time; 1014 1015 // the how_early calculate here doesn't include scheduling latency because 1016 // we've already been scheduled to handle the buffer 1017 bigtime_t how_early = perf_time - EventLatency() - now; 1018 1019 // if the buffer is late, we ignore it and report the fact to the producer 1020 // who sent it to us 1021 if ((RunMode() != B_OFFLINE) && // lateness doesn't matter in offline mode... 1022 (RunMode() != B_RECORDING) && // ...or in recording mode 1023 (how_early < 0LL)) 1024 { 1025 //mLateBuffers++; 1026 NotifyLateProducer(channel->fInput.source, -how_early, perf_time); 1027 fprintf(stderr," <- LATE BUFFER : %lli\n", how_early); 1028 buffer->Recycle(); 1029 } else { 1030 //WriteBuffer(buffer, *channel); 1031 if(channel->fBuffer != NULL) { 1032 PRINT(("MultiAudioNode::HandleBuffer snoozing recycling channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); 1033 //channel->fBuffer->Recycle(); 1034 snooze(100); 1035 if(channel->fBuffer != NULL) 1036 buffer->Recycle(); 1037 else 1038 channel->fBuffer = buffer; 1039 } else { 1040 //PRINT(("MultiAudioNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); 1041 channel->fBuffer = buffer; 1042 } 1043 } 1044 return B_OK; 1045 } 1046 1047 status_t MultiAudioNode::HandleDataStatus( 1048 const media_timed_event *event, 1049 bigtime_t lateness, 1050 bool realTimeEvent) 1051 { 1052 //CALLED(); 1053 PRINT(("MultiAudioNode::HandleDataStatus status:%li, lateness:%li\n", event->data, lateness)); 1054 switch(event->data) { 1055 case B_DATA_NOT_AVAILABLE: 1056 break; 1057 case B_DATA_AVAILABLE: 1058 break; 1059 case B_PRODUCER_STOPPED: 1060 break; 1061 default: 1062 break; 1063 } 1064 return B_OK; 1065 } 1066 1067 status_t MultiAudioNode::HandleStart( 1068 const media_timed_event *event, 1069 bigtime_t lateness, 1070 bool realTimeEvent) 1071 { 1072 CALLED(); 1073 if (RunState() != B_STARTED) { 1074 1075 } 1076 return B_OK; 1077 } 1078 1079 status_t MultiAudioNode::HandleSeek( 1080 const media_timed_event *event, 1081 bigtime_t lateness, 1082 bool realTimeEvent) 1083 { 1084 CALLED(); 1085 PRINT(("MultiAudioNode::HandleSeek(t=%lld,d=%li,bd=%lld)\n",event->event_time,event->data,event->bigdata)); 1086 return B_OK; 1087 } 1088 1089 status_t MultiAudioNode::HandleWarp( 1090 const media_timed_event *event, 1091 bigtime_t lateness, 1092 bool realTimeEvent) 1093 { 1094 CALLED(); 1095 return B_OK; 1096 } 1097 1098 status_t MultiAudioNode::HandleStop( 1099 const media_timed_event *event, 1100 bigtime_t lateness, 1101 bool realTimeEvent) 1102 { 1103 CALLED(); 1104 // flush the queue so downstreamers don't get any more 1105 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 1106 1107 //StopThread(); 1108 return B_OK; 1109 } 1110 1111 status_t MultiAudioNode::HandleParameter( 1112 const media_timed_event *event, 1113 bigtime_t lateness, 1114 bool realTimeEvent) 1115 { 1116 CALLED(); 1117 return B_OK; 1118 } 1119 1120 // -------------------------------------------------------- // 1121 // implemention of BTimeSource 1122 // -------------------------------------------------------- // 1123 1124 void 1125 MultiAudioNode::SetRunMode(run_mode mode) 1126 { 1127 CALLED(); 1128 PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode)); 1129 //BTimeSource::SetRunMode(mode); 1130 } 1131 1132 status_t 1133 MultiAudioNode::TimeSourceOp(const time_source_op_info &op, void *_reserved) 1134 { 1135 CALLED(); 1136 switch(op.op) { 1137 case B_TIMESOURCE_START: 1138 PRINT(("TimeSourceOp op B_TIMESOURCE_START\n")); 1139 if (RunState() != BMediaEventLooper::B_STARTED) { 1140 fTimeSourceStarted = true; 1141 StartThread(); 1142 1143 media_timed_event startEvent(0, BTimedEventQueue::B_START); 1144 EventQueue()->AddEvent(startEvent); 1145 } 1146 break; 1147 case B_TIMESOURCE_STOP: 1148 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP\n")); 1149 if (RunState() == BMediaEventLooper::B_STARTED) { 1150 media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); 1151 EventQueue()->AddEvent(stopEvent); 1152 fTimeSourceStarted = false; 1153 StopThread(); 1154 PublishTime(0, 0, 0); 1155 } 1156 break; 1157 case B_TIMESOURCE_STOP_IMMEDIATELY: 1158 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP_IMMEDIATELY\n")); 1159 if (RunState() == BMediaEventLooper::B_STARTED) { 1160 media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); 1161 EventQueue()->AddEvent(stopEvent); 1162 fTimeSourceStarted = false; 1163 StopThread(); 1164 PublishTime(0, 0, 0); 1165 } 1166 break; 1167 case B_TIMESOURCE_SEEK: 1168 PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n")); 1169 BroadcastTimeWarp(op.real_time, op.performance_time); 1170 break; 1171 default: 1172 break; 1173 } 1174 return B_OK; 1175 } 1176 1177 // -------------------------------------------------------- // 1178 // implemention of BControllable 1179 // -------------------------------------------------------- // 1180 1181 status_t 1182 MultiAudioNode::GetParameterValue(int32 id, bigtime_t* last_change, void* value, size_t* ioSize) 1183 { 1184 CALLED(); 1185 1186 PRINT(("id : %i\n", id)); 1187 BParameter *parameter = NULL; 1188 for(int32 i=0; i<fWeb->CountParameters(); i++) { 1189 parameter = fWeb->ParameterAt(i); 1190 if(parameter->ID() == id) 1191 break; 1192 } 1193 1194 if(!parameter) { 1195 // Hmmm, we were asked for a parameter that we don't actually 1196 // support. Report an error back to the caller. 1197 PRINT(("\terror - asked for illegal parameter %ld\n", id)); 1198 return B_ERROR; 1199 } 1200 1201 multi_mix_value_info MMVI; 1202 multi_mix_value MMV[2]; 1203 int rval; 1204 MMVI.values = MMV; 1205 id = id - 100; 1206 MMVI.item_count = 0; 1207 1208 if (*ioSize < sizeof(float)) 1209 return B_ERROR; 1210 1211 if(parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { 1212 MMVI.item_count = 1; 1213 MMV[0].id = id; 1214 1215 if(parameter->CountChannels() == 2) { 1216 if (*ioSize < 2*sizeof(float)) 1217 return B_ERROR; 1218 MMVI.item_count = 2; 1219 MMV[1].id = id + 1; 1220 } 1221 1222 } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { 1223 MMVI.item_count = 1; 1224 MMV[0].id = id; 1225 } 1226 1227 if(MMVI.item_count > 0) { 1228 rval = fDevice->DoGetMix(&MMVI); 1229 1230 if (B_OK != rval) { 1231 fprintf(stderr, "Failed on DRIVER_GET_MIX\n"); 1232 } else { 1233 1234 if(parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { 1235 ((float*)value)[0] = MMV[0].gain; 1236 *ioSize = sizeof(float); 1237 1238 if(parameter->CountChannels() == 2) { 1239 ((float*)value)[1] = MMV[1].gain; 1240 *ioSize = 2*sizeof(float); 1241 } 1242 1243 for(uint32 i=0; i < (*ioSize/sizeof(float)); i++) { 1244 PRINT(("B_CONTINUOUS_PARAMETER value[%i] : %f\n", i, ((float*)value)[i])); 1245 } 1246 } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { 1247 1248 BDiscreteParameter *dparameter = (BDiscreteParameter*) parameter; 1249 if(dparameter->CountItems()<=2) { 1250 ((int32*)value)[0] = (MMV[0].enable) ? 1 : 0; 1251 } else { 1252 ((int32*)value)[0] = MMV[0].mux; 1253 } 1254 *ioSize = sizeof(int32); 1255 1256 for(uint32 i=0; i < (*ioSize/sizeof(int32)); i++) { 1257 PRINT(("B_DISCRETE_PARAMETER value[%i] : %i\n", i, ((int32*)value)[i])); 1258 } 1259 } 1260 1261 } 1262 } 1263 return B_OK; 1264 } 1265 1266 void 1267 MultiAudioNode::SetParameterValue(int32 id, bigtime_t performance_time, const void* value, size_t size) 1268 { 1269 CALLED(); 1270 PRINT(("id : %i, performance_time : %lld, size : %i\n", id, performance_time, size)); 1271 BParameter *parameter = NULL; 1272 for(int32 i=0; i<fWeb->CountParameters(); i++) { 1273 parameter = fWeb->ParameterAt(i); 1274 if(parameter->ID() == id) 1275 break; 1276 } 1277 if(parameter) { 1278 multi_mix_value_info MMVI; 1279 multi_mix_value MMV[2]; 1280 int rval; 1281 MMVI.values = MMV; 1282 id = id - 100; 1283 MMVI.item_count = 0; 1284 1285 if(parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { 1286 for(uint32 i=0; i < (size/sizeof(float)); i++) { 1287 PRINT(("B_CONTINUOUS_PARAMETER value[%i] : %f\n", i, ((float*)value)[i])); 1288 } 1289 MMVI.item_count = 1; 1290 MMV[0].id = id; 1291 MMV[0].gain = ((float*)value)[0]; 1292 1293 if(parameter->CountChannels() == 2) { 1294 MMVI.item_count = 2; 1295 MMV[1].id = id + 1; 1296 MMV[1].gain = ((float*)value)[1]; 1297 } 1298 1299 } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { 1300 for(uint32 i=0; i < (size/sizeof(int32)); i++) { 1301 PRINT(("B_DISCRETE_PARAMETER value[%i] : %i\n", i, ((int32*)value)[i])); 1302 } 1303 BDiscreteParameter *dparameter = (BDiscreteParameter*) parameter; 1304 1305 if(dparameter->CountItems()<=2) { 1306 MMVI.item_count = 1; 1307 MMV[0].id = id; 1308 MMV[0].enable = (((int32*)value)[0] == 1) ? true : false; 1309 } else { 1310 MMVI.item_count = 1; 1311 MMV[0].id = id; 1312 MMV[0].mux = ((uint32*)value)[0]; 1313 } 1314 } 1315 1316 if(MMVI.item_count > 0) { 1317 rval = fDevice->DoSetMix(&MMVI); 1318 1319 if (B_OK != rval) 1320 { 1321 fprintf(stderr, "Failed on DRIVER_SET_MIX\n"); 1322 } 1323 } 1324 } 1325 1326 } 1327 1328 BParameterWeb* 1329 MultiAudioNode::MakeParameterWeb() 1330 { 1331 CALLED(); 1332 BParameterWeb* web = new BParameterWeb; 1333 1334 PRINT(("MMCI.control_count : %i\n", fDevice->MMCI.control_count)); 1335 multi_mix_control *MMC = fDevice->MMCI.controls; 1336 1337 for(int i=0; i<fDevice->MMCI.control_count; i++) { 1338 if(MMC[i].flags & B_MULTI_MIX_GROUP && MMC[i].parent == 0) { 1339 PRINT(("NEW_GROUP\n")); 1340 int32 nb = 0; 1341 const char* childName; 1342 if(MMC[i].string != S_null) 1343 childName = multi_string[MMC[i].string]; 1344 else 1345 childName = MMC[i].name; 1346 BParameterGroup *child = web->MakeGroup(childName); 1347 ProcessGroup(child, i, nb); 1348 } 1349 } 1350 1351 return web; 1352 } 1353 1354 void 1355 MultiAudioNode::ProcessGroup(BParameterGroup *group, int32 index, int32 &nbParameters) 1356 { 1357 CALLED(); 1358 multi_mix_control *parent = &fDevice->MMCI.controls[index]; 1359 multi_mix_control *MMC = fDevice->MMCI.controls; 1360 for(int32 i=0; i<fDevice->MMCI.control_count; i++) { 1361 if(MMC[i].parent != parent->id) 1362 continue; 1363 1364 const char* childName; 1365 if(MMC[i].string != S_null) 1366 childName = multi_string[MMC[i].string]; 1367 else 1368 childName = MMC[i].name; 1369 1370 if(MMC[i].flags & B_MULTI_MIX_GROUP) { 1371 PRINT(("NEW_GROUP\n")); 1372 int32 nb = 1; 1373 BParameterGroup *child = group->MakeGroup(childName); 1374 child->MakeNullParameter(MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_WEB_BUFFER_OUTPUT); 1375 ProcessGroup(child, i, nb); 1376 } else if(MMC[i].flags & B_MULTI_MIX_MUX) { 1377 PRINT(("NEW_MUX\n")); 1378 BDiscreteParameter *parameter = 1379 group->MakeDiscreteParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_INPUT_MUX); 1380 if(nbParameters>0) { 1381 (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); 1382 nbParameters++; 1383 } 1384 ProcessMux(parameter, i); 1385 } else if(MMC[i].flags & B_MULTI_MIX_GAIN) { 1386 PRINT(("NEW_GAIN\n")); 1387 group->MakeContinuousParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, "", B_MASTER_GAIN, 1388 "dB", MMC[i].gain.min_gain, MMC[i].gain.max_gain, MMC[i].gain.granularity); 1389 1390 if(i+1 <fDevice->MMCI.control_count && MMC[i+1].master == MMC[i].id && MMC[i+1].flags & B_MULTI_MIX_GAIN) { 1391 group->ParameterAt(nbParameters)->SetChannelCount( 1392 group->ParameterAt(nbParameters)->CountChannels() + 1); 1393 i++; 1394 } 1395 1396 PRINT(("nb parameters : %d\n", nbParameters)); 1397 if (nbParameters > 0) { 1398 (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); 1399 nbParameters++; 1400 } 1401 } else if(MMC[i].flags & B_MULTI_MIX_ENABLE) { 1402 PRINT(("NEW_ENABLE\n")); 1403 if(MMC[i].string == S_MUTE) 1404 group->MakeDiscreteParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_MUTE); 1405 else 1406 group->MakeDiscreteParameter(100 + MMC[i].id, B_MEDIA_RAW_AUDIO, childName, B_ENABLE); 1407 if(nbParameters>0) { 1408 (group->ParameterAt(nbParameters - 1))->AddOutput(group->ParameterAt(nbParameters)); 1409 nbParameters++; 1410 } 1411 } 1412 } 1413 } 1414 1415 void 1416 MultiAudioNode::ProcessMux(BDiscreteParameter *parameter, int32 index) 1417 { 1418 CALLED(); 1419 multi_mix_control *parent = &fDevice->MMCI.controls[index]; 1420 multi_mix_control *MMC = fDevice->MMCI.controls; 1421 int32 itemIndex = 0; 1422 for(int32 i=0; i<fDevice->MMCI.control_count; i++) { 1423 if(MMC[i].parent != parent->id) 1424 continue; 1425 1426 const char* childName; 1427 if(MMC[i].string != S_null) 1428 childName = multi_string[MMC[i].string]; 1429 else 1430 childName = MMC[i].name; 1431 1432 if(MMC[i].flags & B_MULTI_MIX_MUX_VALUE) { 1433 PRINT(("NEW_MUX_VALUE\n")); 1434 parameter->AddItem(itemIndex, childName); 1435 itemIndex++; 1436 } 1437 } 1438 } 1439 1440 // -------------------------------------------------------- // 1441 // MultiAudioNode specific functions 1442 // -------------------------------------------------------- // 1443 1444 int32 1445 MultiAudioNode::RunThread() 1446 { 1447 CALLED(); 1448 multi_buffer_info MBI;//, oldMBI; 1449 MBI.info_size = sizeof(MBI); 1450 MBI._reserved_0 = 0; 1451 MBI._reserved_1 = 2; 1452 1453 while ( 1 ) { 1454 //acquire buffer if any 1455 if ( acquire_sem_etc( fBuffer_free, 1, B_RELATIVE_TIMEOUT, 0 ) == B_BAD_SEM_ID ) { 1456 return B_OK; 1457 } 1458 1459 //oldMBI = MBI; 1460 1461 //send buffer 1462 fDevice->DoBufferExchange(&MBI); 1463 1464 //PRINT(("MultiAudioNode::RunThread: buffer exchanged\n")); 1465 //PRINT(("MultiAudioNode::RunThread: played_real_time : %i\n", MBI.played_real_time)); 1466 //PRINT(("MultiAudioNode::RunThread: played_frames_count : %i\n", MBI.played_frames_count)); 1467 //PRINT(("MultiAudioNode::RunThread: buffer_cycle : %i\n", MBI.playback_buffer_cycle)); 1468 1469 node_input *input = NULL; 1470 1471 for(int32 i=0; i<fInputs.CountItems(); i++) { 1472 input = (node_input *)fInputs.ItemAt(i); 1473 1474 if((MBI._reserved_0 == input->fChannelId) 1475 && (input->fOldMBI.playback_buffer_cycle != MBI.playback_buffer_cycle 1476 || fDevice->MBL.return_playback_buffers == 1) 1477 && (input->fInput.source != media_source::null 1478 || input->fChannelId == 0)) { 1479 1480 //PRINT(("playback_buffer_cycle ok input : %i %d\n", i, MBI.playback_buffer_cycle)); 1481 1482 input->fBufferCycle = (MBI.playback_buffer_cycle - 1 1483 + fDevice->MBL.return_playback_buffers) % fDevice->MBL.return_playback_buffers; 1484 1485 // update the timesource 1486 if(input->fChannelId==0) { 1487 //PRINT(("updating timesource\n")); 1488 UpdateTimeSource(MBI, input->fOldMBI, *input); 1489 } 1490 1491 input->fOldMBI = MBI; 1492 1493 if(input->fBuffer!=NULL) { 1494 /*memcpy( fDevice->MBL.playback_buffers[input->fBufferCycle][input->fChannelId].base, 1495 input->fBuffer->Data(), input->fBuffer->SizeUsed() );*/ 1496 FillNextBuffer(*input, input->fBuffer); 1497 input->fBuffer->Recycle(); 1498 input->fBuffer = NULL; 1499 } else { 1500 // put zeros in current buffer 1501 if(input->fInput.source != media_source::null) 1502 WriteZeros(*input, input->fBufferCycle); 1503 //PRINT(("MultiAudioNode::Runthread WriteZeros\n")); 1504 } 1505 1506 //mark buffer free 1507 release_sem( fBuffer_free ); 1508 } else { 1509 //PRINT(("playback_buffer_cycle non ok input : %i\n", i)); 1510 } 1511 } 1512 1513 node_output *output = NULL; 1514 for(int32 i=0; i<fOutputs.CountItems(); i++) { 1515 output = (node_output *)fOutputs.ItemAt(i); 1516 1517 // make sure we're both started *and* connected before delivering a buffer 1518 if ((RunState() == BMediaEventLooper::B_STARTED) && (output->fOutput.destination != media_destination::null)) { 1519 if((MBI._reserved_1 == output->fChannelId) 1520 && (output->fOldMBI.record_buffer_cycle != MBI.record_buffer_cycle 1521 || fDevice->MBL.return_record_buffers == 1)) { 1522 //PRINT(("record_buffer_cycle ok\n")); 1523 1524 // Get the next buffer of data 1525 BBuffer* buffer = FillNextBuffer(MBI, *output); 1526 if (buffer) 1527 { 1528 // send the buffer downstream if and only if output is enabled 1529 status_t err = B_ERROR; 1530 if (output->fOutputEnabled) 1531 err = SendBuffer(buffer, output->fOutput.destination); 1532 if (err) { 1533 buffer->Recycle(); 1534 } else { 1535 // track how much media we've delivered so far 1536 size_t nSamples = output->fOutput.format.u.raw_audio.buffer_size 1537 / output->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK; 1538 output->fSamplesSent += nSamples; 1539 } 1540 } 1541 1542 output->fOldMBI = MBI; 1543 } else { 1544 //PRINT(("record_buffer_cycle non ok\n")); 1545 } 1546 } 1547 } 1548 1549 } 1550 1551 return B_OK; 1552 } 1553 1554 void 1555 MultiAudioNode::WriteZeros(node_input &input, uint32 bufferCycle) 1556 { 1557 //CALLED(); 1558 /*int32 samples = input.fInput.format.u.raw_audio.buffer_size; 1559 if(input.fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_UCHAR) { 1560 uint8 *sample = (uint8*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; 1561 for(int32 i = samples-1; i>=0; i--) 1562 *sample++ = 128; 1563 1564 } else { 1565 int32 *sample = (int32*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; 1566 for(int32 i = (samples / 4)-1; i>=0; i--) 1567 *sample++ = 0;*/ 1568 1569 size_t stride = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId].stride; 1570 uint32 channelCount = input.fFormat.u.raw_audio.channel_count; 1571 1572 switch(input.fFormat.u.raw_audio.format) { 1573 case media_raw_audio_format::B_AUDIO_FLOAT: 1574 for(uint32 channel = 0; channel < channelCount; channel++) { 1575 char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; 1576 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1577 *(float*)sample_dest = 0; 1578 sample_dest += stride; 1579 } 1580 } 1581 break; 1582 case media_raw_audio_format::B_AUDIO_INT: 1583 for(uint32 channel = 0; channel < channelCount; channel++) { 1584 char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; 1585 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1586 *(int32*)sample_dest = 0; 1587 sample_dest += stride; 1588 } 1589 } 1590 break; 1591 case media_raw_audio_format::B_AUDIO_SHORT:{ 1592 for(uint32 channel = 0; channel < channelCount; channel++) { 1593 char *sample_dest = fDevice->MBL.playback_buffers[bufferCycle][input.fChannelId + channel].base; 1594 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1595 *(int16*)sample_dest = 0; 1596 sample_dest += stride; 1597 } 1598 } 1599 break; 1600 } 1601 default: 1602 fprintf(stderr, "ERROR in WriteZeros format not handled\n"); 1603 } 1604 1605 } 1606 1607 void 1608 MultiAudioNode::FillWithZeros(node_input &input) 1609 { 1610 CALLED(); 1611 for(int32 i=0; i<fDevice->MBL.return_playback_buffers; i++) 1612 WriteZeros(input, i); 1613 } 1614 1615 void 1616 MultiAudioNode::FillNextBuffer(node_input &input, BBuffer* buffer) 1617 { 1618 switch(input.fInput.format.u.raw_audio.format) { 1619 case media_raw_audio_format::B_AUDIO_FLOAT: 1620 1621 switch(input.fFormat.u.raw_audio.format) { 1622 case media_raw_audio_format::B_AUDIO_FLOAT: 1623 break; 1624 case media_raw_audio_format::B_AUDIO_INT: 1625 break; 1626 case media_raw_audio_format::B_AUDIO_SHORT: 1627 if(input.fInput.format.u.raw_audio.channel_count == 2) { 1628 int16 *sample_dest1 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; 1629 int16 *sample_dest2 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].base; 1630 float *sample_src = (float*)buffer->Data(); 1631 if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == sizeof(int16) 1632 && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == sizeof(int16)) { 1633 //PRINT(("FillNextBuffer : 2 channels strides 2\n")); 1634 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1635 *sample_dest1++ = int16(32767 * *sample_src++); 1636 *sample_dest2++ = int16(32767 * *sample_src++); 1637 } 1638 } else if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == 2 * sizeof(int16) 1639 && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == 2 * sizeof(int16) 1640 && sample_dest1 + 1 == sample_dest2) { 1641 //PRINT(("FillNextBuffer : 2 channels strides 4\n")); 1642 for(uint32 i=2*fDevice->MBL.return_playback_buffer_size; i>0; i--) 1643 *sample_dest1++ = int16(32767 * *sample_src++); 1644 } else { 1645 //PRINT(("FillNextBuffer : 2 channels strides != 2\n")); 1646 size_t stride1 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride / sizeof(int16); 1647 size_t stride2 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride / sizeof(int16); 1648 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1649 *sample_dest1 = int16(32767 * *sample_src++); 1650 *sample_dest2 = int16(32767 * *sample_src++); 1651 sample_dest1 += stride1; 1652 sample_dest2 += stride2; 1653 } 1654 } 1655 } else { 1656 size_t frame_size = input.fInput.format.u.raw_audio.channel_count * sizeof(int16); 1657 size_t stride = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride; 1658 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->MBL.return_playback_buffer_size)); 1659 for(uint32 channel = 0; channel < input.fInput.format.u.raw_audio.channel_count; channel++) { 1660 char *sample_dest = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + channel].base; 1661 //char *sample_src = (char*)buffer->Data() + (input.fInput.format.u.raw_audio.channel_count - 1 - channel) * sizeof(int16); 1662 char *sample_src = (char*)buffer->Data() + channel * sizeof(int16); 1663 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1664 *(int16*)sample_dest = int16(32767 * *(float*)sample_src); 1665 sample_dest += stride; 1666 sample_src += frame_size; 1667 } 1668 } 1669 } 1670 break; 1671 default: 1672 break; 1673 } 1674 1675 break; 1676 case media_raw_audio_format::B_AUDIO_INT: 1677 switch(input.fFormat.u.raw_audio.format) { 1678 case media_raw_audio_format::B_AUDIO_FLOAT: 1679 break; 1680 case media_raw_audio_format::B_AUDIO_INT: { 1681 size_t frame_size = input.fInput.format.u.raw_audio.channel_count * sizeof(int32); 1682 size_t stride = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride; 1683 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->MBL.return_playback_buffer_size)); 1684 for(uint32 channel = 0; channel < input.fInput.format.u.raw_audio.channel_count; channel++) { 1685 char *sample_dest = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + channel].base; 1686 //char *sample_src = (char*)buffer->Data() + (input.fInput.format.u.raw_audio.channel_count - 1 - channel) * sizeof(int16); 1687 char *sample_src = (char*)buffer->Data() + channel * sizeof(int32); 1688 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1689 *(int32*)sample_dest = *(int32*)sample_src; 1690 sample_dest += stride; 1691 sample_src += frame_size; 1692 } 1693 } 1694 } 1695 break; 1696 case media_raw_audio_format::B_AUDIO_SHORT: 1697 break; 1698 default: 1699 break; 1700 } 1701 break; 1702 case media_raw_audio_format::B_AUDIO_SHORT: 1703 1704 switch(input.fFormat.u.raw_audio.format) { 1705 case media_raw_audio_format::B_AUDIO_FLOAT: 1706 break; 1707 case media_raw_audio_format::B_AUDIO_INT: 1708 break; 1709 case media_raw_audio_format::B_AUDIO_SHORT: 1710 if(input.fInput.format.u.raw_audio.channel_count == 2) { 1711 int16 *sample_dest1 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].base; 1712 int16 *sample_dest2 = (int16*)fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].base; 1713 int16 *sample_src = (int16*)buffer->Data(); 1714 if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == sizeof(int16) 1715 && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == sizeof(int16)) { 1716 //PRINT(("FillNextBuffer : 2 channels strides 2\n")); 1717 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1718 *sample_dest1++ = *sample_src++; 1719 *sample_dest2++ = *sample_src++; 1720 } 1721 } else if(fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride == 2 * sizeof(int16) 1722 && fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride == 2 * sizeof(int16) 1723 && sample_dest1 + 1 == sample_dest2) { 1724 //PRINT(("FillNextBuffer : 2 channels strides 4\n")); 1725 memcpy(sample_dest1, sample_src, fDevice->MBL.return_playback_buffer_size * 2 * sizeof(int16)); 1726 } else { 1727 //PRINT(("FillNextBuffer : 2 channels strides != 2\n")); 1728 size_t stride1 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride / 2; 1729 size_t stride2 = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + 1].stride / 2; 1730 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1731 *sample_dest1 = *sample_src++; 1732 *sample_dest2 = *sample_src++; 1733 sample_dest1 += stride1; 1734 sample_dest2 += stride2; 1735 } 1736 } 1737 } else { 1738 size_t frame_size = input.fInput.format.u.raw_audio.channel_count * sizeof(int16); 1739 size_t stride = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId].stride; 1740 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->MBL.return_playback_buffer_size)); 1741 for(uint32 channel = 0; channel < input.fInput.format.u.raw_audio.channel_count; channel++) { 1742 char *sample_dest = fDevice->MBL.playback_buffers[input.fBufferCycle][input.fChannelId + channel].base; 1743 //char *sample_src = (char*)buffer->Data() + (input.fInput.format.u.raw_audio.channel_count - 1 - channel) * sizeof(int16); 1744 char *sample_src = (char*)buffer->Data() + channel * sizeof(int16); 1745 for(uint32 i=fDevice->MBL.return_playback_buffer_size; i>0; i--) { 1746 *(int16*)sample_dest = *(int16*)sample_src; 1747 sample_dest += stride; 1748 sample_src += frame_size; 1749 } 1750 } 1751 } 1752 break; 1753 default: 1754 break; 1755 } 1756 1757 break; 1758 case media_raw_audio_format::B_AUDIO_UCHAR: 1759 default: 1760 break; 1761 } 1762 } 1763 1764 status_t 1765 MultiAudioNode::StartThread() 1766 { 1767 CALLED(); 1768 // the thread is already started ? 1769 if(fThread > B_OK) 1770 return B_OK; 1771 1772 //allocate buffer free semaphore 1773 fBuffer_free = create_sem( fDevice->MBL.return_playback_buffers - 1, "multi_audio out buffer free" ); 1774 1775 if ( fBuffer_free < B_OK ) { 1776 return B_ERROR; 1777 } 1778 1779 fThread = spawn_thread( _run_thread_, "multi_audio audio output", B_REAL_TIME_PRIORITY, this ); 1780 1781 if ( fThread < B_OK ) { 1782 delete_sem( fBuffer_free ); 1783 return B_ERROR; 1784 } 1785 1786 resume_thread( fThread ); 1787 1788 return B_OK; 1789 } 1790 1791 status_t 1792 MultiAudioNode::StopThread() 1793 { 1794 CALLED(); 1795 delete_sem( fBuffer_free ); 1796 wait_for_thread( fThread, &fThread ); 1797 return B_OK; 1798 } 1799 1800 void 1801 MultiAudioNode::AllocateBuffers(node_output &channel) 1802 { 1803 CALLED(); 1804 1805 // allocate enough buffers to span our downstream latency, plus one 1806 size_t size = channel.fOutput.format.u.raw_audio.buffer_size; 1807 int32 count = int32(fLatency / BufferDuration() + 1 + 1); 1808 1809 PRINT(("\tlatency = %Ld, buffer duration = %Ld\n", fLatency, BufferDuration())); 1810 PRINT(("\tcreating group of %ld buffers, size = %lu\n", count, size)); 1811 channel.fBufferGroup = new BBufferGroup(size, count); 1812 } 1813 1814 void 1815 MultiAudioNode::UpdateTimeSource(multi_buffer_info &MBI, multi_buffer_info &oldMBI, node_input &input) 1816 { 1817 //CALLED(); 1818 if(fTimeSourceStarted) { 1819 bigtime_t perf_time = (bigtime_t)(MBI.played_frames_count / 1820 input.fInput.format.u.raw_audio.frame_rate * 1000000); 1821 bigtime_t real_time = MBI.played_real_time; 1822 float drift = ((MBI.played_frames_count - oldMBI.played_frames_count) 1823 / input.fInput.format.u.raw_audio.frame_rate * 1000000) 1824 / (MBI.played_real_time - oldMBI.played_real_time); 1825 1826 PublishTime(perf_time, real_time, drift); 1827 //PRINT(("UpdateTimeSource() perf_time : %lli, real_time : %lli, drift : %f\n", perf_time, real_time, drift)); 1828 } 1829 } 1830 1831 BBuffer* 1832 MultiAudioNode::FillNextBuffer(multi_buffer_info &MBI, node_output &channel) 1833 { 1834 //CALLED(); 1835 // get a buffer from our buffer group 1836 //PRINT(("buffer size : %i, buffer duration : %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration())); 1837 //PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle)); 1838 //PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time)); 1839 //PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count)); 1840 if(!channel.fBufferGroup) 1841 return NULL; 1842 1843 BBuffer* buffer = channel.fBufferGroup->RequestBuffer(channel.fOutput.format.u.raw_audio.buffer_size, BufferDuration()); 1844 1845 // if we fail to get a buffer (for example, if the request times out), we skip this 1846 // buffer and go on to the next, to avoid locking up the control thread 1847 if (!buffer) 1848 return NULL; 1849 1850 if(fDevice==NULL) 1851 fprintf(stderr,"fDevice NULL\n"); 1852 if(buffer->Header()==NULL) 1853 fprintf(stderr,"buffer->Header() NULL\n"); 1854 if(TimeSource()==NULL) 1855 fprintf(stderr,"TimeSource() NULL\n"); 1856 1857 // now fill it with data, continuing where the last buffer left off 1858 memcpy( buffer->Data(), 1859 fDevice->MBL.record_buffers[MBI.record_buffer_cycle][channel.fChannelId - fDevice->MD.output_channel_count].base, 1860 channel.fOutput.format.u.raw_audio.buffer_size ); 1861 1862 // fill in the buffer header 1863 media_header* hdr = buffer->Header(); 1864 hdr->type = B_MEDIA_RAW_AUDIO; 1865 hdr->size_used = channel.fOutput.format.u.raw_audio.buffer_size; 1866 hdr->time_source = TimeSource()->ID(); 1867 hdr->start_time = PerformanceTimeFor(MBI.recorded_real_time); 1868 1869 return buffer; 1870 } 1871 1872 status_t 1873 MultiAudioNode::GetConfigurationFor(BMessage * into_message) 1874 { 1875 CALLED(); 1876 1877 BParameter *parameter = NULL; 1878 void *buffer; 1879 size_t size = 128; 1880 bigtime_t last_change; 1881 status_t err; 1882 1883 if(!into_message) 1884 return B_BAD_VALUE; 1885 1886 buffer = malloc(size); 1887 1888 for(int32 i=0; i<fWeb->CountParameters(); i++) { 1889 parameter = fWeb->ParameterAt(i); 1890 if(parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER 1891 && parameter->Type() != BParameter::B_DISCRETE_PARAMETER) 1892 continue; 1893 1894 PRINT(("getting parameter %i\n", parameter->ID())); 1895 size = 128; 1896 while((err = GetParameterValue(parameter->ID(), &last_change, buffer, &size))==B_NO_MEMORY) { 1897 size += 128; 1898 free(buffer); 1899 buffer = malloc(size); 1900 } 1901 1902 if(err == B_OK && size > 0) { 1903 into_message->AddInt32("parameterID", parameter->ID()); 1904 into_message->AddData("parameterData", B_RAW_TYPE, buffer, size, false); 1905 } else { 1906 PRINT(("parameter err : %s\n", strerror(err))); 1907 } 1908 } 1909 1910 PRINT_OBJECT(*into_message); 1911 1912 return B_OK; 1913 } 1914 1915 node_output* 1916 MultiAudioNode::FindOutput(media_source source) 1917 { 1918 node_output *channel = NULL; 1919 1920 for(int32 i=0; i<fOutputs.CountItems(); i++) { 1921 channel = (node_output *)fOutputs.ItemAt(i); 1922 if(source == channel->fOutput.source) 1923 break; 1924 } 1925 1926 if (source != channel->fOutput.source) 1927 return NULL; 1928 else 1929 return channel; 1930 1931 } 1932 1933 node_input* 1934 MultiAudioNode::FindInput(media_destination dest) 1935 { 1936 node_input *channel = NULL; 1937 1938 for(int32 i=0; i<fInputs.CountItems(); i++) { 1939 channel = (node_input *)fInputs.ItemAt(i); 1940 if(dest == channel->fInput.destination) 1941 break; 1942 } 1943 1944 if (dest != channel->fInput.destination) 1945 return NULL; 1946 else 1947 return channel; 1948 1949 } 1950 1951 node_input* 1952 MultiAudioNode::FindInput(int32 destinationId) 1953 { 1954 node_input *channel = NULL; 1955 1956 for(int32 i=0; i<fInputs.CountItems(); i++) { 1957 channel = (node_input *)fInputs.ItemAt(i); 1958 if(destinationId == channel->fInput.destination.id) 1959 break; 1960 } 1961 1962 if (destinationId != channel->fInput.destination.id) 1963 return NULL; 1964 else 1965 return channel; 1966 1967 } 1968 1969 // static: 1970 1971 int32 1972 MultiAudioNode::_run_thread_( void *data ) 1973 { 1974 CALLED(); 1975 return static_cast<MultiAudioNode *>( data )->RunThread(); 1976 } 1977 1978 void MultiAudioNode::GetFlavor(flavor_info * outInfo, int32 id) 1979 { 1980 CALLED(); 1981 if (outInfo == 0) { 1982 return; 1983 } 1984 1985 outInfo->flavor_flags = 0; 1986 outInfo->possible_count = 1; // one flavor at a time 1987 outInfo->in_format_count = 0; // no inputs 1988 outInfo->in_formats = 0; 1989 outInfo->out_format_count = 0; // no outputs 1990 outInfo->out_formats = 0; 1991 outInfo->internal_id = id; 1992 1993 outInfo->name = "MultiAudioNode Node"; 1994 outInfo->info = "The MultiAudioNode node outputs to multi_audio drivers."; 1995 outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE 1996 | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE; 1997 outInfo->in_format_count = 1; // 1 input 1998 media_format * informats = new media_format[outInfo->in_format_count]; 1999 GetFormat(&informats[0]); 2000 outInfo->in_formats = informats; 2001 2002 outInfo->out_format_count = 1; // 1 output 2003 media_format * outformats = new media_format[outInfo->out_format_count]; 2004 GetFormat(&outformats[0]); 2005 outInfo->out_formats = outformats; 2006 } 2007 2008 void MultiAudioNode::GetFormat(media_format * outFormat) 2009 { 2010 CALLED(); 2011 if (outFormat == 0) { 2012 return; 2013 } 2014 outFormat->type = B_MEDIA_RAW_AUDIO; 2015 outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 2016 outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 2017 outFormat->u.raw_audio = media_raw_audio_format::wildcard; 2018 } 2019