15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/audio_unified_win.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <Functiondiscoverykeys_devpkey.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h" 10a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/file_util.h" 12a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/path_service.h" 13a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_com_initializer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/audio_manager_win.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/avrt_wrapper_win.h" 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/win/core_audio_util_win.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::ScopedComPtr; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::ScopedCOMInitializer; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::ScopedCoMem; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Smoothing factor in exponential smoothing filter where 0 < alpha < 1. 25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Larger values of alpha reduce the level of smoothing. 26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// See http://en.wikipedia.org/wiki/Exponential_smoothing for details. 27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const double kAlpha = 0.1; 28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Compute a rate compensation which always attracts us back to a specified 30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// target level over a period of |kCorrectionTimeSeconds|. 31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const double kCorrectionTimeSeconds = 0.1; 32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Max number of columns in the output text file |kUnifiedAudioDebugFileName|. 35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// See LogElementNames enumerator for details on what each column represents. 36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const size_t kMaxNumSampleTypes = 4; 37a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 38a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const size_t kMaxNumParams = 2; 39a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Max number of rows in the output file |kUnifiedAudioDebugFileName|. 41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Each row corresponds to one set of sample values for (approximately) the 42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// same time instant (stored in the first column). 43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const size_t kMaxFileSamples = 10000; 44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Name of output debug file used for off-line analysis of measurements which 46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// can be utilized for performance tuning of this class. 47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const char kUnifiedAudioDebugFileName[] = "unified_win_debug.txt"; 48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Name of output debug file used for off-line analysis of measurements. 50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// This file will contain a list of audio parameters. 51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static const char kUnifiedAudioParamsFileName[] = "unified_win_params.txt"; 52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use the acquired IAudioClock interface to derive a time stamp of the audio 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// sample which is currently playing through the speakers. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static double SpeakerStreamPosInMilliseconds(IAudioClock* clock) { 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UINT64 device_frequency = 0, position = 0; 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(clock->GetFrequency(&device_frequency)) || 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FAILED(clock->GetPosition(&position, NULL))) { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0.0; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::Time::kMillisecondsPerSecond * 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (static_cast<double>(position) / device_frequency); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Get a time stamp in milliseconds given number of audio frames in |num_frames| 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// using the current sample rate |fs| as scale factor. 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Example: |num_frames| = 960 and |fs| = 48000 => 20 [ms]. 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static double CurrentStreamPosInMilliseconds(UINT64 num_frames, DWORD fs) { 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return base::Time::kMillisecondsPerSecond * 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (static_cast<double>(num_frames) / fs); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Convert a timestamp in milliseconds to byte units given the audio format 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// in |format|. 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Example: |ts_milliseconds| equals 10, sample rate is 48000 and frame size 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is 4 bytes per audio frame => 480 * 4 = 1920 [bytes]. 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static int MillisecondsToBytes(double ts_milliseconds, 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const WAVEFORMATPCMEX& format) { 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) double seconds = ts_milliseconds / base::Time::kMillisecondsPerSecond; 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return static_cast<int>(seconds * format.Format.nSamplesPerSec * 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) format.Format.nBlockAlign + 0.5); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// Convert frame count to milliseconds given the audio format in |format|. 86a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)static double FrameCountToMilliseconds(int num_frames, 87a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const WAVEFORMATPCMEX& format) { 88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return (base::Time::kMillisecondsPerSecond * num_frames) / 89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) static_cast<double>(format.Format.nSamplesPerSec); 90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace media { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WASAPIUnifiedStream::WASAPIUnifiedStream(AudioManagerWin* manager, 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const AudioParameters& params, 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const std::string& input_device_id) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : creating_thread_id_(base::PlatformThread::CurrentId()), 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manager_(manager), 99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) params_(params), 100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_channels_(params.input_channels()), 101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_channels_(params.channels()), 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) input_device_id_(input_device_id), 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) share_mode_(CoreAudioUtil::GetShareMode()), 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opened_(false), 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) volume_(1.0), 106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_buffer_size_frames_(0), 107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_buffer_size_frames_(0), 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) endpoint_render_buffer_size_frames_(0), 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) endpoint_capture_buffer_size_frames_(0), 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_written_frames_(0), 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) total_delay_ms_(0.0), 112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) total_delay_bytes_(0), 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source_(NULL), 114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_callback_received_(false), 115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) io_sample_rate_ratio_(1), 116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) target_fifo_frames_(0), 117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) average_delta_(0), 118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_compensation_(1), 119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) update_output_delay_(false), 120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) capture_delay_ms_(0) { 121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::WASAPIUnifiedStream"); 122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "WASAPIUnifiedStream::WASAPIUnifiedStream()"; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(manager_); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Input channels : " << input_channels_; 126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Output channels: " << output_channels_; 127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Sample rate : " << params_.sample_rate(); 128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Buffer size : " << params.frames_per_buffer(); 129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_time_stamps_.reset(new int64[kMaxFileSamples]); 132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_frames_in_fifo_.reset(new int[kMaxFileSamples]); 133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_margin_.reset(new int[kMaxFileSamples]); 134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_comps_.reset(new double[kMaxFileSamples]); 135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_elements_.reset(new int[kMaxNumSampleTypes]); 136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) std::fill(num_elements_.get(), num_elements_.get() + kMaxNumSampleTypes, 0); 137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_params_.reset(new int[kMaxNumParams]); 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_params_.reset(new int[kMaxNumParams]); 139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG_IF(1, share_mode_ == AUDCLNT_SHAREMODE_EXCLUSIVE) 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "Core Audio (WASAPI) EXCLUSIVE MODE is enabled."; 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load the Avrt DLL if not already loaded. Required to support MMCSS. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool avrt_init = avrt::Initialize(); 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(avrt_init) << "Failed to load the avrt.dll"; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // All events are auto-reset events and non-signaled initially. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the event which the audio engine will signal each time a buffer 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // has been recorded. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the event which will be set in Stop() when straeming shall stop. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stop_streaming_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WASAPIUnifiedStream::~WASAPIUnifiedStream() { 159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "WASAPIUnifiedStream::~WASAPIUnifiedStream()"; 160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::FilePath data_file_name; 162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) PathService::Get(base::DIR_EXE, &data_file_name); 163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) data_file_name = data_file_name.AppendASCII(kUnifiedAudioDebugFileName); 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) data_file_ = base::OpenFile(data_file_name, "wt"); 165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << ">> Output file " << data_file_name.value() << " is created."; 166a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 167a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t n = 0; 168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t elements_to_write = *std::min_element( 169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_elements_.get(), num_elements_.get() + kMaxNumSampleTypes); 170a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) while (n < elements_to_write) { 171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fprintf(data_file_, "%I64d %d %d %10.9f\n", 172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_time_stamps_[n], 173a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_frames_in_fifo_[n], 174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_margin_[n], 175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_comps_[n]); 176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ++n; 177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(data_file_); 179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::FilePath param_file_name; 181a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) PathService::Get(base::DIR_EXE, ¶m_file_name); 182a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) param_file_name = param_file_name.AppendASCII(kUnifiedAudioParamsFileName); 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) param_file_ = base::OpenFile(param_file_name, "wt"); 184a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << ">> Output file " << param_file_name.value() << " is created."; 185a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fprintf(param_file_, "%d %d\n", input_params_[0], input_params_[1]); 186a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fprintf(param_file_, "%d %d\n", output_params_[0], output_params_[1]); 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::CloseFile(param_file_); 188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WASAPIUnifiedStream::Open() { 192a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::Open"); 193a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << "WASAPIUnifiedStream::Open()"; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (opened_) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 198a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) AudioParameters hw_output_params; 199a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( 200a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) eRender, eConsole, &hw_output_params); 201a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (FAILED(hr)) { 202a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) LOG(ERROR) << "Failed to get preferred output audio parameters."; 203a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return false; 204a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 205a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 206a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) AudioParameters hw_input_params; 207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (input_device_id_ == AudioManagerBase::kDefaultDeviceId) { 208eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Query native parameters for the default capture device. 209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hr = CoreAudioUtil::GetPreferredAudioParameters( 210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch eCapture, eConsole, &hw_input_params); 211eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Query native parameters for the capture device given by 213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // |input_device_id_|. 214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch hr = CoreAudioUtil::GetPreferredAudioParameters( 215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch input_device_id_, &hw_input_params); 216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 217a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (FAILED(hr)) { 218a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) LOG(ERROR) << "Failed to get preferred input audio parameters."; 219a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return false; 220a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 221a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 222a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // It is currently only possible to open up the output audio device using 223a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the native number of channels. 224a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (output_channels_ != hw_output_params.channels()) { 225a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) LOG(ERROR) << "Audio device does not support requested output channels."; 226a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return false; 227a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 228a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 229a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // It is currently only possible to open up the input audio device using 230a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the native number of channels. If the client asks for a higher channel 231a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // count, we will do channel upmixing in this class. The most typical 232a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // example is that the client provides stereo but the hardware can only be 233a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // opened in mono mode. We will do mono to stereo conversion in this case. 234a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (input_channels_ < hw_input_params.channels()) { 235a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) LOG(ERROR) << "Audio device does not support requested input channels."; 236a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return false; 237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else if (input_channels_ > hw_input_params.channels()) { 238a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ChannelLayout input_layout = 239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) GuessChannelLayout(hw_input_params.channels()); 240a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ChannelLayout output_layout = GuessChannelLayout(input_channels_); 241a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) channel_mixer_.reset(new ChannelMixer(input_layout, output_layout)); 242a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << "Remixing input channel layout from " << input_layout 243a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << " to " << output_layout << "; from " 244a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << hw_input_params.channels() << " channels to " 245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << input_channels_; 246a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 247a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 248a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (hw_output_params.sample_rate() != params_.sample_rate()) { 249a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() 250a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << " must match the hardware sample-rate: " 251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << hw_output_params.sample_rate(); 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (hw_output_params.frames_per_buffer() != params_.frames_per_buffer()) { 256a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) LOG(ERROR) << "Requested buffer size: " << params_.frames_per_buffer() 257a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << " must match the hardware buffer size: " 258a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << hw_output_params.frames_per_buffer(); 259a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return false; 260a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 261a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 262a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Set up WAVEFORMATPCMEX structures for input and output given the specified 263a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // audio parameters. 264a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) SetIOFormats(hw_input_params, params_); 265a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 266a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Create the input and output busses. 267a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_bus_ = AudioBus::Create( 268a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) hw_input_params.channels(), input_buffer_size_frames_); 269a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_bus_ = AudioBus::Create(params_); 270a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 271a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // One extra bus is needed for the input channel mixing case. 272a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (channel_mixer_) { 273a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DCHECK_LT(hw_input_params.channels(), input_channels_); 2747d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // The size of the |channel_bus_| must be the same as the size of the 2757d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // output bus to ensure that the channel manager can deal with both 2767d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // resampled and non-resampled data as input. 2777d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) channel_bus_ = AudioBus::Create( 2787d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) input_channels_, params_.frames_per_buffer()); 279a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 280a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 281a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Check if FIFO and resampling is required to match the input rate to the 282a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // output rate. If so, a special thread loop, optimized for this case, will 283a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // be used. This mode is also called varispeed mode. 284a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Note that we can also use this mode when input and output rates are the 285a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // same but native buffer sizes differ (can happen if two different audio 286a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // devices are used). For this case, the resampler uses a target ratio of 287a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // 1.0 but SetRatio is called to compensate for clock-drift. The FIFO is 288a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // required to compensate for the difference in buffer sizes. 289a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // TODO(henrika): we could perhaps improve the performance for the second 290a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // case here by only using the FIFO and avoid resampling. Not sure how much 291a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // that would give and we risk not compensation for clock drift. 292a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (hw_input_params.sample_rate() != params_.sample_rate() || 293a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) hw_input_params.frames_per_buffer() != params_.frames_per_buffer()) { 294a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DoVarispeedInitialization(hw_input_params, params_); 295a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 296a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 297a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Render side (event driven only in varispeed mode): 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IAudioClient> audio_output_client = 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CoreAudioUtil::CreateDefaultClient(eRender, eConsole); 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!audio_output_client) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!CoreAudioUtil::IsFormatSupported(audio_output_client, 3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) share_mode_, 306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &output_format_)) { 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 311a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // The |render_event_| will be NULL unless varispeed mode is utilized. 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = CoreAudioUtil::SharedModeInitialize( 313a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) audio_output_client, &output_format_, render_event_.Get(), 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &endpoint_render_buffer_size_frames_); 3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(henrika): add support for AUDCLNT_SHAREMODE_EXCLUSIVE. 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedComPtr<IAudioRenderClient> audio_render_client = 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CoreAudioUtil::CreateRenderClient(audio_output_client); 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!audio_render_client) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 326a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Capture side (always event driven but format depends on varispeed or not): 327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedComPtr<IAudioClient> audio_input_client; 329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (input_device_id_ == AudioManagerBase::kDefaultDeviceId) { 330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_input_client = CoreAudioUtil::CreateDefaultClient(eCapture, eConsole); 331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ScopedComPtr<IMMDevice> audio_input_device( 333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CoreAudioUtil::CreateDevice(input_device_id_)); 334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch audio_input_client = CoreAudioUtil::CreateClient(audio_input_device); 335eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!audio_input_client) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!CoreAudioUtil::IsFormatSupported(audio_input_client, 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) share_mode_, 341a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &input_format_)) { 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Include valid event handle for event-driven initialization. 347a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // The input side is always event driven independent of if varispeed is 348a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // used or not. 3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) hr = CoreAudioUtil::SharedModeInitialize( 350a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) audio_input_client, &input_format_, capture_event_.Get(), 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &endpoint_capture_buffer_size_frames_); 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(henrika): add support for AUDCLNT_SHAREMODE_EXCLUSIVE. 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (FAILED(hr)) 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedComPtr<IAudioCaptureClient> audio_capture_client = 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CoreAudioUtil::CreateCaptureClient(audio_input_client); 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!audio_capture_client) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 363a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Varispeed mode requires additional preparations. 364a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (VarispeedMode()) 365a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ResetVarispeed(); 366a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Store all valid COM interfaces. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_output_client_ = audio_output_client; 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_render_client_ = audio_render_client; 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_input_client_ = audio_input_client; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_capture_client_ = audio_capture_client; 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) opened_ = true; 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return SUCCEEDED(hr); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::Start(AudioSourceCallback* callback) { 378a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::Start"); 379a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << "WASAPIUnifiedStream::Start()"; 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(callback); 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(opened_); 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (audio_io_thread_) { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_EQ(callback, source_); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source_ = callback; 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 391a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (VarispeedMode()) { 392a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ResetVarispeed(); 393a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_compensation_ = 1.0; 394a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) average_delta_ = 0.0; 395a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_callback_received_ = false; 396a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) update_output_delay_ = false; 397a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 398a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 399a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Create and start the thread that will listen for capture events. 400a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // We will also listen on render events on the same thread if varispeed 401a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // mode is utilized. 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_.reset( 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new base::DelegateSimpleThread(this, "wasapi_io_thread")); 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_->Start(); 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!audio_io_thread_->HasBeenStarted()) { 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Failed to start WASAPI IO thread."; 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start input streaming data between the endpoint buffer and the audio 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // engine. 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = audio_input_client_->Start(); 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAndJoinThread(hr); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Ensure that the endpoint buffer is prepared with silence. 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) audio_output_client_, audio_render_client_)) { 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DLOG(WARNING) << "Failed to prepare endpoint buffers with silence."; 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) num_written_frames_ = endpoint_render_buffer_size_frames_; 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start output streaming data between the endpoint buffer and the audio 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // engine. 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = audio_output_client_->Start(); 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StopAndJoinThread(hr); 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::Stop() { 438a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::Stop"); 439a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << "WASAPIUnifiedStream::Stop()"; 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!audio_io_thread_) 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop input audio streaming. 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HRESULT hr = audio_input_client_->Stop(); 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Failed to stop input streaming: " << std::hex << hr; 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop output audio streaming. 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = audio_output_client_->Stop(); 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Failed to stop output streaming: " << std::hex << hr; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait until the thread completes and perform cleanup. 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEvent(stop_streaming_event_.Get()); 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_->Join(); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_.reset(); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that we don't quit the main thread loop immediately next 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // time Start() is called. 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResetEvent(stop_streaming_event_.Get()); 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clear source callback, it'll be set again on the next Start() call. 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source_ = NULL; 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Flush all pending data and reset the audio clock stream position to 0. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hr = audio_output_client_->Reset(); 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Failed to reset output streaming: " << std::hex << hr; 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_input_client_->Reset(); 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (FAILED(hr)) { 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "Failed to reset input streaming: " << std::hex << hr; 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Extra safety check to ensure that the buffers are cleared. 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the buffers are not cleared correctly, the next call to Start() 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer(). 4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(henrika): this check is is only needed for shared-mode streams. 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT32 num_queued_frames = 0; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_output_client_->GetCurrentPadding(&num_queued_frames); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(0u, num_queued_frames); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::Close() { 493a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::Close"); 494a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << "WASAPIUnifiedStream::Close()"; 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is valid to call Close() before calling open or Start(). 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is also valid to call Close() after Start() has been called. 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Stop(); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Inform the audio manager that we have been closed. This will cause our 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // destruction. 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manager_->ReleaseOutputStream(this); 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::SetVolume(double volume) { 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "SetVolume(volume=" << volume << ")"; 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (volume < 0 || volume > 1) 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) volume_ = volume; 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::GetVolume(double* volume) { 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "GetVolume()"; 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *volume = static_cast<double>(volume_); 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 519a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void WASAPIUnifiedStream::ProvideInput(int frame_delay, AudioBus* audio_bus) { 520a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // TODO(henrika): utilize frame_delay? 521a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // A non-zero framed delay means multiple callbacks were necessary to 522a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // fulfill the requested number of frames. 523a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (frame_delay > 0) 524a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(3) << "frame_delay: " << frame_delay; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 526a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 527a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_margin_[num_elements_[RESAMPLER_MARGIN]] = 528a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_->frames() - audio_bus->frames(); 529a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_elements_[RESAMPLER_MARGIN]++; 530a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 531a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 532a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (fifo_->frames() < audio_bus->frames()) { 533a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(ERROR) << "Not enough data in the FIFO (" 534a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << fifo_->frames() << " < " << audio_bus->frames() << ")"; 535a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) audio_bus->Zero(); 536a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return; 537a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 538a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 539a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_->Consume(audio_bus, 0, audio_bus->frames()); 540a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 541a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 542a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void WASAPIUnifiedStream::SetIOFormats(const AudioParameters& input_params, 543a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const AudioParameters& output_params) { 544a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) for (int n = 0; n < 2; ++n) { 545a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const AudioParameters& params = (n == 0) ? input_params : output_params; 546a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) WAVEFORMATPCMEX* xformat = (n == 0) ? &input_format_ : &output_format_; 547a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) WAVEFORMATEX* format = &xformat->Format; 548a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 549a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Begin with the WAVEFORMATEX structure that specifies the basic format. 550a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->wFormatTag = WAVE_FORMAT_EXTENSIBLE; 551a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->nChannels = params.channels(); 552a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->nSamplesPerSec = params.sample_rate(); 553a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->wBitsPerSample = params.bits_per_sample(); 554a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->nBlockAlign = (format->wBitsPerSample / 8) * format->nChannels; 555a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; 556a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); 557a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 558a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Add the parts which are unique to WAVE_FORMAT_EXTENSIBLE. 559a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Note that we always open up using the native channel layout. 560a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) (*xformat).Samples.wValidBitsPerSample = format->wBitsPerSample; 5611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) (*xformat).dwChannelMask = 5621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) CoreAudioUtil::GetChannelConfig( 5631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string(), n == 0 ? eCapture : eRender); 564a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) (*xformat).SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 565a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 566a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 567a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_buffer_size_frames_ = input_params.frames_per_buffer(); 568a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_buffer_size_frames_ = output_params.frames_per_buffer(); 569a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "#audio frames per input buffer : " << input_buffer_size_frames_; 570a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "#audio frames per output buffer: " << output_buffer_size_frames_; 571a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 572a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 573a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_params_[0] = input_format_.Format.nSamplesPerSec; 574a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_params_[1] = input_buffer_size_frames_; 575a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_params_[0] = output_format_.Format.nSamplesPerSec; 576a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_params_[1] = output_buffer_size_frames_; 577a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 578a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 579a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 580a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void WASAPIUnifiedStream::DoVarispeedInitialization( 581a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const AudioParameters& input_params, const AudioParameters& output_params) { 582a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(1) << "WASAPIUnifiedStream::DoVarispeedInitialization()"; 583a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 584a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // A FIFO is required in this mode for input to output buffering. 585a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Note that it will add some latency. 586a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_.reset(new AudioFifo(input_params.channels(), kFifoSize)); 587a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Using FIFO of size " << fifo_->max_frames() 588a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << " (#channels=" << input_params.channels() << ")"; 589a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 590a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Create the multi channel resampler using the initial sample rate ratio. 591a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // We will call MultiChannelResampler::SetRatio() during runtime to 592a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // allow arbitrary combinations of input and output devices running off 593a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // different clocks and using different drivers, with potentially 594a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // differing sample-rates. Note that the requested block size is given by 595a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the native input buffer size |input_buffer_size_frames_|. 596a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) io_sample_rate_ratio_ = input_params.sample_rate() / 597a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) static_cast<double>(output_params.sample_rate()); 598a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(2) << "io_sample_rate_ratio: " << io_sample_rate_ratio_; 599a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_.reset(new MultiChannelResampler( 600a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_params.channels(), io_sample_rate_ratio_, input_buffer_size_frames_, 601a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::Bind(&WASAPIUnifiedStream::ProvideInput, base::Unretained(this)))); 602a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Resampling from " << input_params.sample_rate() << " to " 603a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) << output_params.sample_rate(); 604a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 605a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // The optimal number of frames we'd like to keep in the FIFO at all times. 606a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // The actual size will vary but the goal is to ensure that the average size 607a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // is given by this value. 608a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) target_fifo_frames_ = kTargetFifoSafetyFactor * input_buffer_size_frames_; 609a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) VLOG(1) << "Target FIFO size: " << target_fifo_frames_; 610a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 611a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Create the event which the audio engine will signal each time it 612a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // wants an audio buffer to render. 613a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); 614a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 615a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Allocate memory for temporary audio bus used to store resampled input 616a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // audio. 617a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampled_bus_ = AudioBus::Create( 618a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_params.channels(), output_buffer_size_frames_); 619a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 620a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Buffer initial silence corresponding to target I/O buffering. 621a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ResetVarispeed(); 622a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 623a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 624a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void WASAPIUnifiedStream::ResetVarispeed() { 625a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DCHECK(VarispeedMode()); 626a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 627a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Buffer initial silence corresponding to target I/O buffering. 628a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_->Clear(); 629a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) scoped_ptr<AudioBus> silence = 630a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) AudioBus::Create(input_format_.Format.nChannels, 631a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) target_fifo_frames_); 632a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) silence->Zero(); 633a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_->Push(silence.get()); 634a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_->Flush(); 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::Run() { 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Increase the thread priority. 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enable MMCSS to ensure that this thread receives prioritized access to 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CPU resources. 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(henrika): investigate if it is possible to include these additional 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // settings in SetThreadPriority() as well. 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD task_index = 0; 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HANDLE mm_task = avrt::AvSetMmThreadCharacteristics(L"Pro Audio", 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &task_index); 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool mmcss_is_ok = 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (mm_task && avrt::AvSetMmThreadPriority(mm_task, AVRT_PRIORITY_CRITICAL)); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!mmcss_is_ok) { 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Failed to enable MMCSS on this thread. It is not fatal but can lead 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to reduced QoS at high load. 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD err = GetLastError(); 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ")."; 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The IAudioClock interface enables us to monitor a stream's data 6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // rate and the current position in the stream. Allocate it before we 6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // start spinning. 6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ScopedComPtr<IAudioClock> audio_output_clock; 6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) HRESULT hr = audio_output_client_->GetService( 6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) __uuidof(IAudioClock), audio_output_clock.ReceiveVoid()); 6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) LOG_IF(WARNING, FAILED(hr)) << "Failed to create IAudioClock: " 6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << std::hex << hr; 6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool streaming = true; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool error = false; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 671a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) HANDLE wait_array[3]; 672a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) size_t num_handles = 0; 673a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wait_array[num_handles++] = stop_streaming_event_; 674a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wait_array[num_handles++] = capture_event_; 675a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (render_event_) { 676a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // One extra event handle is needed in varispeed mode. 677a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) wait_array[num_handles++] = render_event_; 678a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 680a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Keep streaming audio until stop event is signaled. 681a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Capture events are always used but render events are only active in 682a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // varispeed mode. 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (streaming && !error) { 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wait for a close-down event, or a new capture event. 685a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DWORD wait_result = WaitForMultipleObjects(num_handles, 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wait_array, 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FALSE, 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) INFINITE); 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (wait_result) { 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case WAIT_OBJECT_0 + 0: 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |stop_streaming_event_| has been set. 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) streaming = false; 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case WAIT_OBJECT_0 + 1: 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |capture_event_| has been set 696a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (VarispeedMode()) { 697a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ProcessInputAudio(); 698a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 699a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ProcessInputAudio(); 700a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ProcessOutputAudio(audio_output_clock); 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 703a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) case WAIT_OBJECT_0 + 2: 704a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DCHECK(VarispeedMode()); 705a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |render_event_| has been set 706a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) ProcessOutputAudio(audio_output_clock); 707a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) break; 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error = true; 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (streaming && error) { 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Stop audio streaming since something has gone wrong in our main thread 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // loop. Note that, we are still in a "started" state, hence a Stop() call 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is required to join the thread properly. 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_input_client_->Stop(); 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_output_client_->Stop(); 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLOG(ERROR) << "WASAPI streaming failed."; 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Disable MMCSS. 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) { 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PLOG(WARNING) << "Failed to disable MMCSS"; 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 729a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void WASAPIUnifiedStream::ProcessInputAudio() { 730a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::ProcessInputAudio"); 731a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 732a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) BYTE* data_ptr = NULL; 733a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) UINT32 num_captured_frames = 0; 734a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DWORD flags = 0; 735a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) UINT64 device_position = 0; 736a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) UINT64 capture_time_stamp = 0; 737a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 738a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const int bytes_per_sample = input_format_.Format.wBitsPerSample >> 3; 739a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 740a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::TimeTicks now_tick = base::TimeTicks::HighResNow(); 741a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 742a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 743a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (VarispeedMode()) { 744a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_time_stamps_[num_elements_[INPUT_TIME_STAMP]] = 745a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) now_tick.ToInternalValue(); 746a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_elements_[INPUT_TIME_STAMP]++; 747a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 748a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 749a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 750a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Retrieve the amount of data in the capture endpoint buffer. 751a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |endpoint_capture_time_stamp| is the value of the performance 752a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // counter at the time that the audio endpoint device recorded 753a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the device position of the first audio frame in the data packet. 754a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) HRESULT hr = audio_capture_client_->GetBuffer(&data_ptr, 755a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &num_captured_frames, 756a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &flags, 757a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &device_position, 758a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &capture_time_stamp); 759a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (FAILED(hr)) { 760a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DLOG(ERROR) << "Failed to get data from the capture buffer"; 761a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return; 762a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 763a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 764a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (hr == AUDCLNT_S_BUFFER_EMPTY) { 765a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // The return coded is a success code but a new packet is *not* available 766a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // and none of the output parameters in the GetBuffer() call contains valid 767a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // values. Best we can do is to deliver silence and avoid setting 768a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |input_callback_received_| since this only seems to happen for the 769a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // initial event(s) on some devices. 770a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_bus_->Zero(); 771a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 772a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Valid data has been recorded and it is now OK to set the flag which 773a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // informs the render side that capturing has started. 774a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_callback_received_ = true; 775a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 776a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 777a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (num_captured_frames != 0) { 778a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { 779a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Clear out the capture buffer since silence is reported. 780a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_bus_->Zero(); 781a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } else { 782a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Store captured data in an audio bus after de-interleaving 783a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the data to match the audio bus structure. 784a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_bus_->FromInterleaved( 785a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) data_ptr, num_captured_frames, bytes_per_sample); 786a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 787a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 788a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 789a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) hr = audio_capture_client_->ReleaseBuffer(num_captured_frames); 790a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DLOG_IF(ERROR, FAILED(hr)) << "Failed to release capture buffer"; 791a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 792a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Buffer input into FIFO if varispeed mode is used. The render event 793a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // will drive resampling of this data to match the output side. 794a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (VarispeedMode()) { 795a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) int available_frames = fifo_->max_frames() - fifo_->frames(); 796a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (input_bus_->frames() <= available_frames) { 797a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_->Push(input_bus_.get()); 798a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 799a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 800a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_frames_in_fifo_[num_elements_[NUM_FRAMES_IN_FIFO]] = 801a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_->frames(); 802a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_elements_[NUM_FRAMES_IN_FIFO]++; 803a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 804a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 805a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 806a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Save resource by not asking for new delay estimates each time. 807a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // These estimates are fairly stable and it is perfectly safe to only 808a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // sample at a rate of ~1Hz. 809a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // TODO(henrika): we might have to increase the update rate in varispeed 810a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // mode since the delay variations are higher in this mode. 811a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if ((now_tick - last_delay_sample_time_).InMilliseconds() > 812a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) kTimeDiffInMillisecondsBetweenDelayMeasurements && 813a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_callback_received_) { 814a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Calculate the estimated capture delay, i.e., the latency between 815a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the recording time and the time we when we are notified about 816a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the recorded data. Note that the capture time stamp is given in 817a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // 100-nanosecond (0.1 microseconds) units. 818a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::TimeDelta diff = 819a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) now_tick - base::TimeTicks::FromInternalValue(0.1 * capture_time_stamp); 820a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) capture_delay_ms_ = diff.InMillisecondsF(); 821a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 822a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) last_delay_sample_time_ = now_tick; 823a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) update_output_delay_ = true; 824a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 825a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 826a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 827a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)void WASAPIUnifiedStream::ProcessOutputAudio(IAudioClock* audio_output_clock) { 828a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) TRACE_EVENT0("audio", "WASAPIUnifiedStream::ProcessOutputAudio"); 829a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 830a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (!input_callback_received_) { 831a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 832a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( 833a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) audio_output_client_, audio_render_client_)) 834a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DLOG(WARNING) << "Failed to prepare endpoint buffers with silence."; 835a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 836a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return; 837a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 838a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 839a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Rate adjusted resampling is required in varispeed mode. It means that 840a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // recorded audio samples will be read from the FIFO, resampled to match the 841a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // output sample-rate and then stored in |resampled_bus_|. 842a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (VarispeedMode()) { 843a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Calculate a varispeed rate scalar factor to compensate for drift between 844a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // input and output. We use the actual number of frames still in the FIFO 845a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // compared with the ideal value of |target_fifo_frames_|. 846a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) int delta = fifo_->frames() - target_fifo_frames_; 847a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 848a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Average |delta| because it can jitter back/forth quite frequently 849a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // by +/- the hardware buffer-size *if* the input and output callbacks are 850a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // happening at almost exactly the same time. Also, if the input and output 851a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // sample-rates are different then |delta| will jitter quite a bit due to 852a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the rate conversion happening in the varispeed, plus the jittering of 853a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // the callbacks. The average value is what's important here. 854a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // We use an exponential smoothing filter to reduce the variations. 855a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) average_delta_ += kAlpha * (delta - average_delta_); 856a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 857a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Compute a rate compensation which always attracts us back to the 858a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |target_fifo_frames_| over a period of kCorrectionTimeSeconds. 859a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) double correction_time_frames = 860a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) kCorrectionTimeSeconds * output_format_.Format.nSamplesPerSec; 861a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_compensation_ = 862a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) (correction_time_frames + average_delta_) / correction_time_frames; 863a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 864a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#ifndef NDEBUG 865a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_comps_[num_elements_[RATE_COMPENSATION]] = 866a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) fifo_rate_compensation_; 867a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_elements_[RATE_COMPENSATION]++; 868a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#endif 869a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 870a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Adjust for FIFO drift. 871a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const double new_ratio = io_sample_rate_ratio_ * fifo_rate_compensation_; 872a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_->SetRatio(new_ratio); 873a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Get resampled input audio from FIFO where the size is given by the 874a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // output side. 875a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampler_->Resample(resampled_bus_->frames(), resampled_bus_.get()); 876a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 877a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 878a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Derive a new total delay estimate if the capture side has set the 879a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |update_output_delay_| flag. 880a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (update_output_delay_) { 881a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Calculate the estimated render delay, i.e., the time difference 882a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // between the time when data is added to the endpoint buffer and 883a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // when the data is played out on the actual speaker. 884a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const double stream_pos = CurrentStreamPosInMilliseconds( 885a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_written_frames_ + output_buffer_size_frames_, 886a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_format_.Format.nSamplesPerSec); 887a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const double speaker_pos = 888a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) SpeakerStreamPosInMilliseconds(audio_output_clock); 889a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const double render_delay_ms = stream_pos - speaker_pos; 890a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const double fifo_delay_ms = VarispeedMode() ? 891a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) FrameCountToMilliseconds(target_fifo_frames_, input_format_) : 0; 892a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 893a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Derive the total delay, i.e., the sum of the input and output 894a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // delays. Also convert the value into byte units. An extra FIFO delay 895a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // is added for varispeed usage cases. 896a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) total_delay_ms_ = VarispeedMode() ? 897a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) capture_delay_ms_ + render_delay_ms + fifo_delay_ms : 898a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) capture_delay_ms_ + render_delay_ms; 899a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(2) << "total_delay_ms : " << total_delay_ms_; 900a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(3) << " capture_delay_ms: " << capture_delay_ms_; 901a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(3) << " render_delay_ms : " << render_delay_ms; 902a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DVLOG(3) << " fifo_delay_ms : " << fifo_delay_ms; 903a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) total_delay_bytes_ = MillisecondsToBytes(total_delay_ms_, output_format_); 904a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 905a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Wait for new signal from the capture side. 906a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) update_output_delay_ = false; 907a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 908a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 909a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Select source depending on if varispeed is utilized or not. 910a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Also, the source might be the output of a channel mixer if channel mixing 911a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // is required to match the native input channels to the number of input 912a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // channels used by the client (given by |input_channels_| in this case). 913a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) AudioBus* input_bus = VarispeedMode() ? 914a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) resampled_bus_.get() : input_bus_.get(); 915a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (channel_mixer_) { 9167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_EQ(input_bus->frames(), channel_bus_->frames()); 917a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Most common case is 1->2 channel upmixing. 918a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) channel_mixer_->Transform(input_bus, channel_bus_.get()); 919a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Use the output from the channel mixer as new input bus. 920a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_bus = channel_bus_.get(); 921a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 922a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 923a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Prepare for rendering by calling OnMoreIOData(). 924a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) int frames_filled = source_->OnMoreIOData( 925a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) input_bus, 926a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_bus_.get(), 927a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) AudioBuffersState(0, total_delay_bytes_)); 928a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DCHECK_EQ(frames_filled, output_bus_->frames()); 929a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 930a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Keep track of number of rendered frames since we need it for 931a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // our delay calculations. 932a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) num_written_frames_ += frames_filled; 933a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 934a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Derive the the amount of available space in the endpoint buffer. 935a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Avoid render attempt if there is no room for a captured packet. 936a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) UINT32 num_queued_frames = 0; 937a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) audio_output_client_->GetCurrentPadding(&num_queued_frames); 938a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (endpoint_render_buffer_size_frames_ - num_queued_frames < 939a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_buffer_size_frames_) 940a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return; 941a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 942a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Grab all available space in the rendering endpoint buffer 943a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // into which the client can write a data packet. 944a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) uint8* audio_data = NULL; 945a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) HRESULT hr = audio_render_client_->GetBuffer(output_buffer_size_frames_, 946a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) &audio_data); 947a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if (FAILED(hr)) { 948a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DLOG(ERROR) << "Failed to access render buffer"; 949a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return; 950a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) } 951a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 952a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const int bytes_per_sample = output_format_.Format.wBitsPerSample >> 3; 953a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 954a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Convert the audio bus content to interleaved integer data using 955a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // |audio_data| as destination. 956a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_bus_->Scale(volume_); 957a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_bus_->ToInterleaved( 958a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) output_buffer_size_frames_, bytes_per_sample, audio_data); 959a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 960a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) // Release the buffer space acquired in the GetBuffer() call. 961a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) audio_render_client_->ReleaseBuffer(output_buffer_size_frames_, 0); 962a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) DLOG_IF(ERROR, FAILED(hr)) << "Failed to release render buffer"; 963a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 964a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return; 965a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 966a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::HandleError(HRESULT err) { 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK((started() && GetCurrentThreadId() == audio_io_thread_->tid()) || 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (!started() && GetCurrentThreadId() == creating_thread_id_)); 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Error code: " << std::hex << err; 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (source_) 9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) source_->OnError(this); 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WASAPIUnifiedStream::StopAndJoinThread(HRESULT err) { 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(GetCurrentThreadId() == creating_thread_id_); 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(audio_io_thread_.get()); 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetEvent(stop_streaming_event_.Get()); 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_->Join(); 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) audio_io_thread_.reset(); 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HandleError(err); 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 985