| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 DCHECK_EQ(new_channel_count_mode_, channel_count_mode_); | 83 DCHECK_EQ(new_channel_count_mode_, channel_count_mode_); |
| 84 DCHECK_EQ(new_channel_interpretation_, channel_interpretation_); | 84 DCHECK_EQ(new_channel_interpretation_, channel_interpretation_); |
| 85 | 85 |
| 86 is_initialized_ = true; | 86 is_initialized_ = true; |
| 87 } | 87 } |
| 88 | 88 |
| 89 void AudioHandler::Uninitialize() { | 89 void AudioHandler::Uninitialize() { |
| 90 is_initialized_ = false; | 90 is_initialized_ = false; |
| 91 } | 91 } |
| 92 | 92 |
| 93 void AudioHandler::ClearInternalStateWhenDisabled() {} | |
| 94 | |
| 95 void AudioHandler::Dispose() { | 93 void AudioHandler::Dispose() { |
| 96 DCHECK(IsMainThread()); | 94 DCHECK(IsMainThread()); |
| 97 DCHECK(Context()->IsGraphOwner()); | 95 DCHECK(Context()->IsGraphOwner()); |
| 98 | 96 |
| 99 Context()->GetDeferredTaskHandler().RemoveChangedChannelCountMode(this); | 97 Context()->GetDeferredTaskHandler().RemoveChangedChannelCountMode(this); |
| 100 Context()->GetDeferredTaskHandler().RemoveChangedChannelInterpretation(this); | 98 Context()->GetDeferredTaskHandler().RemoveChangedChannelInterpretation(this); |
| 101 Context()->GetDeferredTaskHandler().RemoveAutomaticPullNode(this); | 99 Context()->GetDeferredTaskHandler().RemoveAutomaticPullNode(this); |
| 102 for (auto& output : outputs_) | 100 for (auto& output : outputs_) |
| 103 output->Dispose(); | 101 output->Dispose(); |
| 104 node_ = nullptr; | 102 node_ = nullptr; |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 // have the results cached in their bus; | 316 // have the results cached in their bus; |
| 319 double current_time = Context()->currentTime(); | 317 double current_time = Context()->currentTime(); |
| 320 if (last_processing_time_ != current_time) { | 318 if (last_processing_time_ != current_time) { |
| 321 // important to first update this time because of feedback loops in the | 319 // important to first update this time because of feedback loops in the |
| 322 // rendering graph. | 320 // rendering graph. |
| 323 last_processing_time_ = current_time; | 321 last_processing_time_ = current_time; |
| 324 | 322 |
| 325 PullInputs(frames_to_process); | 323 PullInputs(frames_to_process); |
| 326 | 324 |
| 327 bool silent_inputs = InputsAreSilent(); | 325 bool silent_inputs = InputsAreSilent(); |
| 328 if (!silent_inputs) { | |
| 329 last_non_silent_time_ = | |
| 330 (Context()->CurrentSampleFrame() + frames_to_process) / | |
| 331 static_cast<double>(Context()->sampleRate()); | |
| 332 } | |
| 333 | |
| 334 if (silent_inputs && PropagatesSilence()) { | 326 if (silent_inputs && PropagatesSilence()) { |
| 335 SilenceOutputs(); | 327 SilenceOutputs(); |
| 336 // AudioParams still need to be processed so that the value can be updated | 328 // AudioParams still need to be processed so that the value can be updated |
| 337 // if there are automations or so that the upstream nodes get pulled if | 329 // if there are automations or so that the upstream nodes get pulled if |
| 338 // any are connected to the AudioParam. | 330 // any are connected to the AudioParam. |
| 339 ProcessOnlyAudioParams(frames_to_process); | 331 ProcessOnlyAudioParams(frames_to_process); |
| 340 } else { | 332 } else { |
| 341 // Unsilence the outputs first because the processing of the node may | 333 // Unsilence the outputs first because the processing of the node may |
| 342 // cause the outputs to go silent and we want to propagate that hint to | 334 // cause the outputs to go silent and we want to propagate that hint to |
| 343 // the downstream nodes. (For example, a Gain node with a gain of 0 will | 335 // the downstream nodes. (For example, a Gain node with a gain of 0 will |
| 344 // want to silence its output.) | 336 // want to silence its output.) |
| 345 UnsilenceOutputs(); | 337 UnsilenceOutputs(); |
| 346 Process(frames_to_process); | 338 Process(frames_to_process); |
| 347 } | 339 } |
| 340 |
| 341 if (!silent_inputs) { |
| 342 // Update last_non_silent_time AFTER processing this block. |
| 343 // Doing it before causes PropagateSilence to be one render |
| 344 // quantum longer than necessary. |
| 345 last_non_silent_time_ = |
| 346 (Context()->CurrentSampleFrame() + frames_to_process) / |
| 347 static_cast<double>(Context()->sampleRate()); |
| 348 } |
| 348 } | 349 } |
| 349 } | 350 } |
| 350 | 351 |
| 351 void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) { | 352 void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) { |
| 352 DCHECK(Context()->IsAudioThread()); | 353 DCHECK(Context()->IsAudioThread()); |
| 353 DCHECK(Context()->IsGraphOwner()); | 354 DCHECK(Context()->IsGraphOwner()); |
| 354 | 355 |
| 355 DCHECK(inputs_.Contains(input)); | 356 DCHECK(inputs_.Contains(input)); |
| 356 if (!inputs_.Contains(input)) | 357 if (!inputs_.Contains(input)) |
| 357 return; | 358 return; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 DCHECK(IsMainThread()); | 396 DCHECK(IsMainThread()); |
| 396 BaseAudioContext::AutoLocker locker(Context()); | 397 BaseAudioContext::AutoLocker locker(Context()); |
| 397 | 398 |
| 398 is_disabled_ = false; | 399 is_disabled_ = false; |
| 399 for (auto& output : outputs_) | 400 for (auto& output : outputs_) |
| 400 output->Enable(); | 401 output->Enable(); |
| 401 } | 402 } |
| 402 } | 403 } |
| 403 | 404 |
| 404 void AudioHandler::DisableOutputsIfNecessary() { | 405 void AudioHandler::DisableOutputsIfNecessary() { |
| 406 // This function calls other functions that require graph ownership, |
| 407 // so assert that this needs graph ownership too. |
| 408 DCHECK(Context()->IsGraphOwner()); |
| 409 |
| 405 // Disable outputs if appropriate. We do this if the number of connections is | 410 // Disable outputs if appropriate. We do this if the number of connections is |
| 406 // 0 or 1. The case of 0 is from deref() where there are no connections left. | 411 // 0 or 1. The case of 0 is from deref() where there are no connections left. |
| 407 // The case of 1 is from AudioNodeInput::disable() where we want to disable | 412 // The case of 1 is from AudioNodeInput::disable() where we want to disable |
| 408 // outputs when there's only one connection left because we're ready to go | 413 // outputs when there's only one connection left because we're ready to go |
| 409 // away, but can't quite yet. | 414 // away, but can't quite yet. |
| 410 if (connection_ref_count_ <= 1 && !is_disabled_) { | 415 if (connection_ref_count_ <= 1 && !is_disabled_) { |
| 411 // Still may have JavaScript references, but no more "active" connection | 416 // Still may have JavaScript references, but no more "active" connection |
| 412 // references, so put all of our outputs in a "dormant" disabled state. | 417 // references, so put all of our outputs in a "dormant" disabled state. |
| 413 // Garbage collection may take a very long time after this time, so the | 418 // Garbage collection may take a very long time after this time, so the |
| 414 // "dormant" disabled nodes should not bog down the rendering... | 419 // "dormant" disabled nodes should not bog down the rendering... |
| 415 | 420 |
| 416 // As far as JavaScript is concerned, our outputs must still appear to be | 421 // As far as JavaScript is concerned, our outputs must still appear to be |
| 417 // connected. But internally our outputs should be disabled from the inputs | 422 // connected. But internally our outputs should be disabled from the inputs |
| 418 // they're connected to. disable() can recursively deref connections (and | 423 // they're connected to. disable() can recursively deref connections (and |
| 419 // call disable()) down a whole chain of connected nodes. | 424 // call disable()) down a whole chain of connected nodes. |
| 420 | 425 |
| 421 // TODO(rtoy,hongchan): we need special cases the convolver, delay, biquad, | 426 // If a node requires tail processing, we defer the disabling of |
| 422 // and IIR since they have a significant tail-time and shouldn't be | 427 // the outputs so that the tail for the node can be output. |
| 423 // disconnected simply because they no longer have any input connections. | 428 // Otherwise, we can disable the outputs right away. |
| 424 // This needs to be handled more generally where AudioNodes have a tailTime | 429 if (RequiresTailProcessing()) { |
| 425 // attribute. Then the AudioNode only needs to remain "active" for tailTime | 430 if (Context()->ContextState() != |
| 426 // seconds after there are no longer any active connections. | 431 BaseAudioContext::AudioContextState::kClosed) { |
| 427 // | 432 Context()->GetDeferredTaskHandler().AddTailProcessingNode(this); |
| 428 // The analyser node also requires special handling because we | 433 } |
| 429 // need the internal state to be updated for the time and FFT data | 434 } else { |
| 430 // even if it has no connections. | 435 ReallyDisableOutputs(); |
| 431 if (GetNodeType() != kNodeTypeConvolver && | |
| 432 GetNodeType() != kNodeTypeDelay && | |
| 433 GetNodeType() != kNodeTypeBiquadFilter && | |
| 434 GetNodeType() != kNodeTypeIIRFilter && | |
| 435 GetNodeType() != kNodeTypeAnalyser) { | |
| 436 is_disabled_ = true; | |
| 437 ClearInternalStateWhenDisabled(); | |
| 438 for (auto& output : outputs_) | |
| 439 output->Disable(); | |
| 440 } | 436 } |
| 441 } | 437 } |
| 442 } | 438 } |
| 443 | 439 |
| 440 void AudioHandler::ReallyDisableOutputs() { |
| 441 is_disabled_ = true; |
| 442 for (auto& output : outputs_) |
| 443 output->Disable(); |
| 444 } |
| 445 |
| 444 void AudioHandler::MakeConnection() { | 446 void AudioHandler::MakeConnection() { |
| 445 AtomicIncrement(&connection_ref_count_); | 447 AtomicIncrement(&connection_ref_count_); |
| 446 | 448 |
| 449 Context()->GetDeferredTaskHandler().RemoveTailProcessingNode(this); |
| 450 |
| 447 #if DEBUG_AUDIONODE_REFERENCES | 451 #if DEBUG_AUDIONODE_REFERENCES |
| 448 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::ref %3d [%3d]\n", | 452 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::ref %3d [%3d] @%.15g\n", |
| 449 Context(), this, GetNodeType(), connection_ref_count_, | 453 Context(), this, GetNodeType(), connection_ref_count_, |
| 450 node_count_[GetNodeType()]); | 454 node_count_[GetNodeType()], Context()->currentTime()); |
| 451 #endif | 455 #endif |
| 452 // See the disabling code in disableOutputsIfNecessary(). This handles | 456 // See the disabling code in disableOutputsIfNecessary(). This handles |
| 453 // the case where a node is being re-connected after being used at least | 457 // the case where a node is being re-connected after being used at least |
| 454 // once and disconnected. In this case, we need to re-enable. | 458 // once and disconnected. In this case, we need to re-enable. |
| 455 EnableOutputsIfNecessary(); | 459 EnableOutputsIfNecessary(); |
| 456 } | 460 } |
| 457 | 461 |
| 458 void AudioHandler::BreakConnection() { | 462 void AudioHandler::BreakConnection() { |
| 459 // The actual work for deref happens completely within the audio context's | 463 // The actual work for deref happens completely within the audio context's |
| 460 // graph lock. In the case of the audio thread, we must use a tryLock to | 464 // graph lock. In the case of the audio thread, we must use a tryLock to |
| (...skipping 15 matching lines...) Expand all Loading... |
| 476 // later. | 480 // later. |
| 477 DCHECK(Context()->IsAudioThread()); | 481 DCHECK(Context()->IsAudioThread()); |
| 478 Context()->GetDeferredTaskHandler().AddDeferredBreakConnection(*this); | 482 Context()->GetDeferredTaskHandler().AddDeferredBreakConnection(*this); |
| 479 } | 483 } |
| 480 } | 484 } |
| 481 | 485 |
| 482 void AudioHandler::BreakConnectionWithLock() { | 486 void AudioHandler::BreakConnectionWithLock() { |
| 483 AtomicDecrement(&connection_ref_count_); | 487 AtomicDecrement(&connection_ref_count_); |
| 484 | 488 |
| 485 #if DEBUG_AUDIONODE_REFERENCES | 489 #if DEBUG_AUDIONODE_REFERENCES |
| 486 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::deref %3d [%3d]\n", | 490 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::deref %3d [%3d] @%.15g\n", |
| 487 Context(), this, GetNodeType(), connection_ref_count_, | 491 Context(), this, GetNodeType(), connection_ref_count_, |
| 488 node_count_[GetNodeType()]); | 492 node_count_[GetNodeType()], Context()->currentTime()); |
| 489 #endif | 493 #endif |
| 490 | 494 |
| 491 if (!connection_ref_count_) | 495 if (!connection_ref_count_) |
| 492 DisableOutputsIfNecessary(); | 496 DisableOutputsIfNecessary(); |
| 493 } | 497 } |
| 494 | 498 |
| 495 #if DEBUG_AUDIONODE_REFERENCES | 499 #if DEBUG_AUDIONODE_REFERENCES |
| 496 | 500 |
| 497 bool AudioHandler::is_node_count_initialized_ = false; | 501 bool AudioHandler::is_node_count_initialized_ = false; |
| 498 int AudioHandler::node_count_[kNodeTypeEnd]; | 502 int AudioHandler::node_count_[kNodeTypeEnd]; |
| 499 | 503 |
| 500 void AudioHandler::PrintNodeCounts() { | 504 void AudioHandler::PrintNodeCounts() { |
| 501 fprintf(stderr, "\n\n"); | 505 fprintf(stderr, "\n\n"); |
| 502 fprintf(stderr, "===========================\n"); | 506 fprintf(stderr, "===========================\n"); |
| 503 fprintf(stderr, "AudioNode: reference counts\n"); | 507 fprintf(stderr, "AudioNode: reference counts\n"); |
| 504 fprintf(stderr, "===========================\n"); | 508 fprintf(stderr, "===========================\n"); |
| 505 | 509 |
| 506 for (unsigned i = 0; i < kNodeTypeEnd; ++i) | 510 for (unsigned i = 0; i < kNodeTypeEnd; ++i) |
| 507 fprintf(stderr, "%2d: %d\n", i, node_count_[i]); | 511 fprintf(stderr, "%2d: %d\n", i, node_count_[i]); |
| 508 | 512 |
| 509 fprintf(stderr, "===========================\n\n\n"); | 513 fprintf(stderr, "===========================\n\n\n"); |
| 510 } | 514 } |
| 511 | 515 |
| 512 #endif // DEBUG_AUDIONODE_REFERENCES | 516 #endif // DEBUG_AUDIONODE_REFERENCES |
| 513 | 517 |
| 518 #if DEBUG_AUDIONODE_REFERENCES > 1 |
| 519 void AudioHandler::TailProcessingDebug(const char* note) { |
| 520 fprintf(stderr, "[%16p]: %16p: %2d: %s %d @%.15g", Context(), this, |
| 521 GetNodeType(), note, connection_ref_count_, Context()->currentTime()); |
| 522 |
| 523 // If we're on the audio thread, we can print out the tail and |
| 524 // latency times (because these methods can only be called from the |
| 525 // audio thread.) |
| 526 if (Context()->IsAudioThread()) { |
| 527 fprintf(stderr, ", tail=%.15g + %.15g, last=%.15g\n", TailTime(), |
| 528 LatencyTime(), last_non_silent_time_); |
| 529 } |
| 530 |
| 531 fprintf(stderr, "\n"); |
| 532 } |
| 533 |
| 534 void AudioHandler::AddTailProcessingDebug() { |
| 535 TailProcessingDebug("addTail"); |
| 536 } |
| 537 |
| 538 void AudioHandler::RemoveTailProcessingDebug() { |
| 539 TailProcessingDebug("remTail"); |
| 540 } |
| 541 #endif // DEBUG_AUDIONODE_REFERENCES > 1 |
| 542 |
| 514 void AudioHandler::UpdateChannelCountMode() { | 543 void AudioHandler::UpdateChannelCountMode() { |
| 515 channel_count_mode_ = new_channel_count_mode_; | 544 channel_count_mode_ = new_channel_count_mode_; |
| 516 UpdateChannelsForInputs(); | 545 UpdateChannelsForInputs(); |
| 517 } | 546 } |
| 518 | 547 |
| 519 void AudioHandler::UpdateChannelInterpretation() { | 548 void AudioHandler::UpdateChannelInterpretation() { |
| 520 channel_interpretation_ = new_channel_interpretation_; | 549 channel_interpretation_ = new_channel_interpretation_; |
| 521 } | 550 } |
| 522 | 551 |
| 523 unsigned AudioHandler::NumberOfOutputChannels() const { | 552 unsigned AudioHandler::NumberOfOutputChannels() const { |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 961 } | 990 } |
| 962 | 991 |
| 963 void AudioNode::DidAddOutput(unsigned number_of_outputs) { | 992 void AudioNode::DidAddOutput(unsigned number_of_outputs) { |
| 964 connected_nodes_.push_back(nullptr); | 993 connected_nodes_.push_back(nullptr); |
| 965 DCHECK_EQ(number_of_outputs, connected_nodes_.size()); | 994 DCHECK_EQ(number_of_outputs, connected_nodes_.size()); |
| 966 connected_params_.push_back(nullptr); | 995 connected_params_.push_back(nullptr); |
| 967 DCHECK_EQ(number_of_outputs, connected_params_.size()); | 996 DCHECK_EQ(number_of_outputs, connected_params_.size()); |
| 968 } | 997 } |
| 969 | 998 |
| 970 } // namespace blink | 999 } // namespace blink |
| OLD | NEW |