Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(799)

Side by Side Diff: media/audio/win/audio_low_latency_output_win.cc

Issue 10970010: Extended sanity checks in WASAPIAudioOutputStream (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/win/audio_low_latency_output_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/win/audio_low_latency_output_win.h" 5 #include "media/audio/win/audio_low_latency_output_win.h"
6 6
7 #include <Functiondiscoverykeys_devpkey.h> 7 #include <Functiondiscoverykeys_devpkey.h>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
382 return AUDCLNT_SHAREMODE_EXCLUSIVE; 382 return AUDCLNT_SHAREMODE_EXCLUSIVE;
383 return AUDCLNT_SHAREMODE_SHARED; 383 return AUDCLNT_SHAREMODE_SHARED;
384 } 384 }
385 385
386 WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager, 386 WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
387 const AudioParameters& params, 387 const AudioParameters& params,
388 ERole device_role) 388 ERole device_role)
389 : creating_thread_id_(base::PlatformThread::CurrentId()), 389 : creating_thread_id_(base::PlatformThread::CurrentId()),
390 manager_(manager), 390 manager_(manager),
391 opened_(false), 391 opened_(false),
392 started_(false),
393 restart_rendering_mode_(false), 392 restart_rendering_mode_(false),
394 volume_(1.0), 393 volume_(1.0),
395 endpoint_buffer_size_frames_(0), 394 endpoint_buffer_size_frames_(0),
396 device_role_(device_role), 395 device_role_(device_role),
397 share_mode_(GetShareMode()), 396 share_mode_(GetShareMode()),
398 client_channel_count_(params.channels()), 397 client_channel_count_(params.channels()),
399 num_written_frames_(0), 398 num_written_frames_(0),
400 source_(NULL), 399 source_(NULL),
401 audio_bus_(AudioBus::Create(params)) { 400 audio_bus_(AudioBus::Create(params)) {
402 DCHECK(manager_); 401 DCHECK(manager_);
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
555 hr = device_enumerator_->RegisterEndpointNotificationCallback(this); 554 hr = device_enumerator_->RegisterEndpointNotificationCallback(this);
556 if (FAILED(hr)) 555 if (FAILED(hr))
557 RecordFallbackStats(); 556 RecordFallbackStats();
558 557
559 opened_ = true; 558 opened_ = true;
560 return SUCCEEDED(hr); 559 return SUCCEEDED(hr);
561 } 560 }
562 561
563 void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) { 562 void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) {
564 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 563 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
565 DCHECK(callback); 564 CHECK(callback);
566 DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully"; 565 CHECK(opened_);
567 if (!opened_) 566
567 if (render_thread_.get()) {
568 CHECK_EQ(callback, source_);
568 return; 569 return;
569 570 }
570 if (started_)
571 return;
572 571
573 if (restart_rendering_mode_) { 572 if (restart_rendering_mode_) {
574 // The selected audio device has been removed or disabled and a new 573 // The selected audio device has been removed or disabled and a new
575 // default device has been enabled instead. The current implementation 574 // default device has been enabled instead. The current implementation
576 // does not to support this sequence of events. Given that Open() 575 // does not to support this sequence of events. Given that Open()
577 // and Start() are usually called in one sequence; it should be a very 576 // and Start() are usually called in one sequence; it should be a very
578 // rare event. 577 // rare event.
579 // TODO(henrika): it is possible to extend the functionality here. 578 // TODO(henrika): it is possible to extend the functionality here.
580 LOG(ERROR) << "Unable to start since the selected default device has " 579 LOG(ERROR) << "Unable to start since the selected default device has "
581 "changed since Open() was called."; 580 "changed since Open() was called.";
(...skipping 21 matching lines...) Expand all
603 // Sanity check: verify that the endpoint buffer is filled with silence. 602 // Sanity check: verify that the endpoint buffer is filled with silence.
604 UINT32 num_queued_frames = 0; 603 UINT32 num_queued_frames = 0;
605 audio_client_->GetCurrentPadding(&num_queued_frames); 604 audio_client_->GetCurrentPadding(&num_queued_frames);
606 DCHECK(num_queued_frames == num_written_frames_); 605 DCHECK(num_queued_frames == num_written_frames_);
607 606
608 // Create and start the thread that will drive the rendering by waiting for 607 // Create and start the thread that will drive the rendering by waiting for
609 // render events. 608 // render events.
610 render_thread_.reset( 609 render_thread_.reset(
611 new base::DelegateSimpleThread(this, "wasapi_render_thread")); 610 new base::DelegateSimpleThread(this, "wasapi_render_thread"));
612 render_thread_->Start(); 611 render_thread_->Start();
613 if (!render_thread_->HasBeenStarted()) {
614 DLOG(ERROR) << "Failed to start WASAPI render thread.";
615 return;
616 }
617 612
618 // Start streaming data between the endpoint buffer and the audio engine. 613 // Start streaming data between the endpoint buffer and the audio engine.
619 hr = audio_client_->Start(); 614 hr = audio_client_->Start();
620 if (FAILED(hr)) { 615 if (FAILED(hr)) {
621 SetEvent(stop_render_event_.Get()); 616 SetEvent(stop_render_event_.Get());
622 render_thread_->Join(); 617 render_thread_->Join();
623 render_thread_.reset(); 618 render_thread_.reset();
624 HandleError(hr); 619 HandleError(hr);
625 return;
626 } 620 }
627
628 started_ = true;
629 } 621 }
630 622
631 void WASAPIAudioOutputStream::Stop() { 623 void WASAPIAudioOutputStream::Stop() {
632 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 624 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
633 if (!started_) 625 if (!render_thread_.get())
634 return; 626 return;
635 627
636 // Shut down the render thread.
637 if (stop_render_event_.IsValid()) {
638 SetEvent(stop_render_event_.Get());
639 }
640
641 // Stop output audio streaming. 628 // Stop output audio streaming.
642 HRESULT hr = audio_client_->Stop(); 629 HRESULT hr = audio_client_->Stop();
643 if (FAILED(hr)) { 630 if (FAILED(hr)) {
644 DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) 631 DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED)
645 << "Failed to stop output streaming: " << std::hex << hr; 632 << "Failed to stop output streaming: " << std::hex << hr;
646 } 633 }
647 634
648 // Wait until the thread completes and perform cleanup. 635 // Wait until the thread completes and perform cleanup.
649 if (render_thread_.get()) { 636 SetEvent(stop_render_event_.Get());
650 SetEvent(stop_render_event_.Get()); 637 render_thread_->Join();
651 render_thread_->Join(); 638 render_thread_.reset();
652 render_thread_.reset(); 639
653 } 640 // Ensure that we don't quit the main thread loop immediately next
641 // time Start() is called.
642 ResetEvent(stop_render_event_.Get());
654 643
655 // Clear source callback, it'll be set again on the next Start() call. 644 // Clear source callback, it'll be set again on the next Start() call.
656 source_ = NULL; 645 source_ = NULL;
657 646
658 // Flush all pending data and reset the audio clock stream position to 0. 647 // Flush all pending data and reset the audio clock stream position to 0.
659 hr = audio_client_->Reset(); 648 hr = audio_client_->Reset();
660 if (FAILED(hr)) { 649 if (FAILED(hr)) {
661 DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) 650 DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED)
662 << "Failed to reset streaming: " << std::hex << hr; 651 << "Failed to reset streaming: " << std::hex << hr;
663 } 652 }
664 653
665 // Extra safety check to ensure that the buffers are cleared. 654 // Extra safety check to ensure that the buffers are cleared.
666 // If the buffers are not cleared correctly, the next call to Start() 655 // If the buffers are not cleared correctly, the next call to Start()
667 // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer(). 656 // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer().
668 // This check is is only needed for shared-mode streams. 657 // This check is is only needed for shared-mode streams.
669 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 658 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
670 UINT32 num_queued_frames = 0; 659 UINT32 num_queued_frames = 0;
671 audio_client_->GetCurrentPadding(&num_queued_frames); 660 audio_client_->GetCurrentPadding(&num_queued_frames);
672 DCHECK_EQ(0u, num_queued_frames); 661 DCHECK_EQ(0u, num_queued_frames);
673 } 662 }
674
675 // Ensure that we don't quit the main thread loop immediately next
676 // time Start() is called.
677 ResetEvent(stop_render_event_.Get());
678
679 started_ = false;
680 } 663 }
681 664
682 void WASAPIAudioOutputStream::Close() { 665 void WASAPIAudioOutputStream::Close() {
683 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 666 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
684 667
685 // It is valid to call Close() before calling open or Start(). 668 // It is valid to call Close() before calling open or Start().
686 // It is also valid to call Close() after Start() has been called. 669 // It is also valid to call Close() after Start() has been called.
687 Stop(); 670 Stop();
688 671
689 if (opened_ && device_enumerator_) { 672 if (opened_ && device_enumerator_) {
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 PLOG(ERROR) << "WASAPI rendering failed."; 975 PLOG(ERROR) << "WASAPI rendering failed.";
993 } 976 }
994 977
995 // Disable MMCSS. 978 // Disable MMCSS.
996 if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) { 979 if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) {
997 PLOG(WARNING) << "Failed to disable MMCSS"; 980 PLOG(WARNING) << "Failed to disable MMCSS";
998 } 981 }
999 } 982 }
1000 983
1001 void WASAPIAudioOutputStream::HandleError(HRESULT err) { 984 void WASAPIAudioOutputStream::HandleError(HRESULT err) {
985 CHECK(started() && (GetCurrentThreadId() == render_thread_->tid() ||
tommi (sloooow) - chröme 2012/09/20 12:15:38 I see you've changed the parenthesis, but the chec
henrika (OOO until Aug 14) 2012/09/20 12:27:19 Done.
986 GetCurrentThreadId() == creating_thread_id_));
1002 NOTREACHED() << "Error code: " << std::hex << err; 987 NOTREACHED() << "Error code: " << std::hex << err;
1003 if (source_) 988 if (source_)
1004 source_->OnError(this, static_cast<int>(err)); 989 source_->OnError(this, static_cast<int>(err));
1005 } 990 }
1006 991
1007 HRESULT WASAPIAudioOutputStream::SetRenderDevice() { 992 HRESULT WASAPIAudioOutputStream::SetRenderDevice() {
1008 ScopedComPtr<IMMDeviceEnumerator> device_enumerator; 993 ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
1009 ScopedComPtr<IMMDevice> endpoint_device; 994 ScopedComPtr<IMMDevice> endpoint_device;
1010 995
1011 // Create the IMMDeviceEnumerator interface. 996 // Create the IMMDeviceEnumerator interface.
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
1428 // are now re-initiated and it is now possible to re-start audio rendering. 1413 // are now re-initiated and it is now possible to re-start audio rendering.
1429 1414
1430 // Start rendering again using the new default audio endpoint. 1415 // Start rendering again using the new default audio endpoint.
1431 hr = audio_client_->Start(); 1416 hr = audio_client_->Start();
1432 1417
1433 restart_rendering_mode_ = false; 1418 restart_rendering_mode_ = false;
1434 return SUCCEEDED(hr); 1419 return SUCCEEDED(hr);
1435 } 1420 }
1436 1421
1437 } // namespace media 1422 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/win/audio_low_latency_output_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698