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

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

Issue 11366241: Removed IMMNotification from WASAPIAudioOutputStream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 1 month 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 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 // All events are auto-reset events and non-signaled initially. 232 // All events are auto-reset events and non-signaled initially.
233 233
234 // Create the event which the audio engine will signal each time 234 // Create the event which the audio engine will signal each time
235 // a buffer becomes ready to be processed by the client. 235 // a buffer becomes ready to be processed by the client.
236 audio_samples_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); 236 audio_samples_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
237 DCHECK(audio_samples_render_event_.IsValid()); 237 DCHECK(audio_samples_render_event_.IsValid());
238 238
239 // Create the event which will be set in Stop() when capturing shall stop. 239 // Create the event which will be set in Stop() when capturing shall stop.
240 stop_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); 240 stop_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
241 DCHECK(stop_render_event_.IsValid()); 241 DCHECK(stop_render_event_.IsValid());
242
243 // Create the event which will be set when a stream switch shall take place.
244 stream_switch_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
245 DCHECK(stream_switch_event_.IsValid());
246 } 242 }
247 243
248 WASAPIAudioOutputStream::~WASAPIAudioOutputStream() {} 244 WASAPIAudioOutputStream::~WASAPIAudioOutputStream() {}
249 245
250 bool WASAPIAudioOutputStream::Open() { 246 bool WASAPIAudioOutputStream::Open() {
251 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 247 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
252 if (opened_) 248 if (opened_)
253 return true; 249 return true;
254 250
255 // Channel mixing is not supported, it must be handled by ChannelMixer. 251 // Channel mixing is not supported, it must be handled by ChannelMixer.
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 // to reduced QoS at high load. 473 // to reduced QoS at high load.
478 DWORD err = GetLastError(); 474 DWORD err = GetLastError();
479 LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ")."; 475 LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ").";
480 } 476 }
481 477
482 HRESULT hr = S_FALSE; 478 HRESULT hr = S_FALSE;
483 479
484 bool playing = true; 480 bool playing = true;
485 bool error = false; 481 bool error = false;
486 HANDLE wait_array[] = { stop_render_event_, 482 HANDLE wait_array[] = { stop_render_event_,
487 stream_switch_event_,
488 audio_samples_render_event_ }; 483 audio_samples_render_event_ };
489 UINT64 device_frequency = 0; 484 UINT64 device_frequency = 0;
490 485
491 // The IAudioClock interface enables us to monitor a stream's data 486 // The IAudioClock interface enables us to monitor a stream's data
492 // rate and the current position in the stream. Allocate it before we 487 // rate and the current position in the stream. Allocate it before we
493 // start spinning. 488 // start spinning.
494 ScopedComPtr<IAudioClock> audio_clock; 489 ScopedComPtr<IAudioClock> audio_clock;
495 hr = audio_client_->GetService(__uuidof(IAudioClock), 490 hr = audio_client_->GetService(__uuidof(IAudioClock),
496 audio_clock.ReceiveVoid()); 491 audio_clock.ReceiveVoid());
497 if (SUCCEEDED(hr)) { 492 if (SUCCEEDED(hr)) {
(...skipping 13 matching lines...) Expand all
511 wait_array, 506 wait_array,
512 FALSE, 507 FALSE,
513 INFINITE); 508 INFINITE);
514 509
515 switch (wait_result) { 510 switch (wait_result) {
516 case WAIT_OBJECT_0 + 0: 511 case WAIT_OBJECT_0 + 0:
517 // |stop_render_event_| has been set. 512 // |stop_render_event_| has been set.
518 playing = false; 513 playing = false;
519 break; 514 break;
520 case WAIT_OBJECT_0 + 1: 515 case WAIT_OBJECT_0 + 1:
521 // |stream_switch_event_| has been set. Stop rendering and try to
522 // re-start the session using a new endpoint device.
523 if (!RestartRenderingUsingNewDefaultDevice()) {
524 // Abort the thread since stream switching failed.
525 playing = false;
526 error = true;
527 }
528 break;
529 case WAIT_OBJECT_0 + 2:
530 { 516 {
531 // |audio_samples_render_event_| has been set. 517 // |audio_samples_render_event_| has been set.
532 UINT32 num_queued_frames = 0; 518 UINT32 num_queued_frames = 0;
533 uint8* audio_data = NULL; 519 uint8* audio_data = NULL;
534 520
535 // Contains how much new data we can write to the buffer without 521 // Contains how much new data we can write to the buffer without
536 // the risk of overwriting previously written data that the audio 522 // the risk of overwriting previously written data that the audio
537 // engine has not yet read from the buffer. 523 // engine has not yet read from the buffer.
538 size_t num_available_frames = 0; 524 size_t num_available_frames = 0;
539 525
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 } else if (hr == AUDCLNT_E_INVALID_DEVICE_PERIOD) { 921 } else if (hr == AUDCLNT_E_INVALID_DEVICE_PERIOD) {
936 // We will get this error if we try to use a smaller buffer size than 922 // We will get this error if we try to use a smaller buffer size than
937 // the minimum supported size (usually ~3ms on Windows 7). 923 // the minimum supported size (usually ~3ms on Windows 7).
938 LOG(ERROR) << "AUDCLNT_E_INVALID_DEVICE_PERIOD"; 924 LOG(ERROR) << "AUDCLNT_E_INVALID_DEVICE_PERIOD";
939 } 925 }
940 } 926 }
941 927
942 return hr; 928 return hr;
943 } 929 }
944 930
945 ULONG WASAPIAudioOutputStream::AddRef() {
946 NOTREACHED() << "IMMNotificationClient should not use this method.";
947 return 1;
948 }
949
950 ULONG WASAPIAudioOutputStream::Release() {
951 NOTREACHED() << "IMMNotificationClient should not use this method.";
952 return 1;
953 }
954
955 HRESULT WASAPIAudioOutputStream::QueryInterface(REFIID iid, void** object) {
956 NOTREACHED() << "IMMNotificationClient should not use this method.";
957 if (iid == IID_IUnknown || iid == __uuidof(IMMNotificationClient)) {
958 *object = static_cast < IMMNotificationClient*>(this);
959 } else {
960 return E_NOINTERFACE;
961 }
962 return S_OK;
963 }
964
965 STDMETHODIMP WASAPIAudioOutputStream::OnDeviceStateChanged(LPCWSTR device_id,
966 DWORD new_state) {
967 #ifndef NDEBUG
968 std::string device_name = GetDeviceName(device_id);
969 std::string device_state;
970
971 switch (new_state) {
972 case DEVICE_STATE_ACTIVE:
973 device_state = "ACTIVE";
974 break;
975 case DEVICE_STATE_DISABLED:
976 device_state = "DISABLED";
977 break;
978 case DEVICE_STATE_NOTPRESENT:
979 device_state = "NOTPRESENT";
980 break;
981 case DEVICE_STATE_UNPLUGGED:
982 device_state = "UNPLUGGED";
983 break;
984 default:
985 break;
986 }
987
988 DVLOG(1) << "-> State changed to " << device_state
989 << " for device: " << device_name;
990 #endif
991 return S_OK;
992 }
993
994 HRESULT WASAPIAudioOutputStream::OnDefaultDeviceChanged(
995 EDataFlow flow, ERole role, LPCWSTR new_default_device_id) {
996 if (new_default_device_id == NULL) {
997 // The user has removed or disabled the default device for our
998 // particular role, and no other device is available to take that role.
999 DLOG(ERROR) << "All devices are disabled.";
1000 return E_FAIL;
1001 }
1002
1003 if (flow == eRender && role == device_role_) {
1004 // Log the name of the new default device for our configured role.
1005 std::string new_default_device = GetDeviceName(new_default_device_id);
1006 DVLOG(1) << "-> New default device: " << new_default_device;
1007
1008 // Initiate a stream switch if not already initiated by signaling the
1009 // stream-switch event to inform the render thread that it is OK to
1010 // re-initialize the active audio renderer. All the action takes place
1011 // on the WASAPI render thread.
1012 if (!restart_rendering_mode_) {
1013 restart_rendering_mode_ = true;
1014 SetEvent(stream_switch_event_.Get());
1015 }
1016 }
1017
1018 return S_OK;
1019 }
1020
1021 std::string WASAPIAudioOutputStream::GetDeviceName(LPCWSTR device_id) const { 931 std::string WASAPIAudioOutputStream::GetDeviceName(LPCWSTR device_id) const {
1022 std::string name; 932 std::string name;
1023 ScopedComPtr<IMMDevice> audio_device; 933 ScopedComPtr<IMMDevice> audio_device;
1024 934
1025 // Get the IMMDevice interface corresponding to the given endpoint ID string. 935 // Get the IMMDevice interface corresponding to the given endpoint ID string.
1026 HRESULT hr = device_enumerator_->GetDevice(device_id, audio_device.Receive()); 936 HRESULT hr = device_enumerator_->GetDevice(device_id, audio_device.Receive());
1027 if (SUCCEEDED(hr)) { 937 if (SUCCEEDED(hr)) {
1028 // Retrieve user-friendly name of endpoint device. 938 // Retrieve user-friendly name of endpoint device.
1029 // Example: "Speakers (Realtek High Definition Audio)". 939 // Example: "Speakers (Realtek High Definition Audio)".
1030 ScopedComPtr<IPropertyStore> properties; 940 ScopedComPtr<IPropertyStore> properties;
1031 hr = audio_device->OpenPropertyStore(STGM_READ, properties.Receive()); 941 hr = audio_device->OpenPropertyStore(STGM_READ, properties.Receive());
1032 if (SUCCEEDED(hr)) { 942 if (SUCCEEDED(hr)) {
1033 PROPVARIANT friendly_name; 943 PROPVARIANT friendly_name;
1034 PropVariantInit(&friendly_name); 944 PropVariantInit(&friendly_name);
1035 hr = properties->GetValue(PKEY_Device_FriendlyName, &friendly_name); 945 hr = properties->GetValue(PKEY_Device_FriendlyName, &friendly_name);
1036 if (SUCCEEDED(hr) && friendly_name.vt == VT_LPWSTR) { 946 if (SUCCEEDED(hr) && friendly_name.vt == VT_LPWSTR) {
1037 if (friendly_name.pwszVal) 947 if (friendly_name.pwszVal)
1038 name = WideToUTF8(friendly_name.pwszVal); 948 name = WideToUTF8(friendly_name.pwszVal);
1039 } 949 }
1040 PropVariantClear(&friendly_name); 950 PropVariantClear(&friendly_name);
1041 } 951 }
1042 } 952 }
1043 return name; 953 return name;
1044 } 954 }
1045 955
1046 bool WASAPIAudioOutputStream::RestartRenderingUsingNewDefaultDevice() {
1047 DCHECK(base::PlatformThread::CurrentId() == render_thread_->tid());
1048 DCHECK(restart_rendering_mode_);
1049
1050 // The |restart_rendering_mode_| event has been signaled which means that
1051 // we must stop the current renderer and start a new render session using
1052 // the new default device with the configured role.
1053
1054 // Stop the current rendering.
1055 HRESULT hr = audio_client_->Stop();
1056 if (FAILED(hr)) {
1057 restart_rendering_mode_ = false;
1058 return false;
1059 }
1060
1061 // Release acquired interfaces (IAudioRenderClient, IAudioClient, IMMDevice).
1062 audio_render_client_.Release();
1063 audio_client_.Release();
1064 endpoint_device_.Release();
1065
1066 // Retrieve the new default render audio endpoint (IMMDevice) for the
1067 // specified role.
1068 hr = device_enumerator_->GetDefaultAudioEndpoint(
1069 eRender, device_role_, endpoint_device_.Receive());
1070 if (FAILED(hr)) {
1071 restart_rendering_mode_ = false;
1072 return false;
1073 }
1074
1075 // Re-create an IAudioClient interface.
1076 hr = ActivateRenderDevice();
1077 if (FAILED(hr)) {
1078 restart_rendering_mode_ = false;
1079 return false;
1080 }
1081
1082 // Retrieve the new mix format and ensure that it is supported given
1083 // the predefined format set at construction.
1084 base::win::ScopedCoMem<WAVEFORMATEX> new_audio_engine_mix_format;
1085 hr = audio_client_->GetMixFormat(&new_audio_engine_mix_format);
1086 if (FAILED(hr) || !DesiredFormatIsSupported()) {
1087 restart_rendering_mode_ = false;
1088 return false;
1089 }
1090
1091 // Re-initialize the audio engine using the new audio endpoint.
1092 // This method will create a new IAudioRenderClient interface.
1093 hr = InitializeAudioEngine();
1094 if (FAILED(hr)) {
1095 restart_rendering_mode_ = false;
1096 return false;
1097 }
1098
1099 // All released interfaces (IAudioRenderClient, IAudioClient, IMMDevice)
1100 // are now re-initiated and it is now possible to re-start audio rendering.
1101
1102 // Start rendering again using the new default audio endpoint.
1103 hr = audio_client_->Start();
1104
1105 restart_rendering_mode_ = false;
1106 return SUCCEEDED(hr);
1107 }
1108
1109 } // namespace media 956 } // 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