summaryrefslogtreecommitdiff
path: root/chromium/media/audio
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-20 10:33:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-11-22 11:45:12 +0000
commitbe59a35641616a4cf23c4a13fa0632624b021c1b (patch)
tree9da183258bdf9cc413f7562079d25ace6955467f /chromium/media/audio
parentd702e4b6a64574e97fc7df8fe3238cde70242080 (diff)
downloadqtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/media/audio')
-rw-r--r--chromium/media/audio/BUILD.gn44
-rw-r--r--chromium/media/audio/OWNERS2
-rw-r--r--chromium/media/audio/alsa/alsa_input.cc21
-rw-r--r--chromium/media/audio/alsa/audio_manager_alsa.cc61
-rw-r--r--chromium/media/audio/alsa/audio_manager_alsa.h3
-rw-r--r--chromium/media/audio/android/audio_android_unittest.cc6
-rw-r--r--chromium/media/audio/android/audio_manager_android.cc28
-rw-r--r--chromium/media/audio/android/audio_manager_android.h7
-rw-r--r--chromium/media/audio/android/audio_record_input.cc16
-rw-r--r--chromium/media/audio/android/audio_record_input.h4
-rw-r--r--chromium/media/audio/android/audio_track_output_stream.cc181
-rw-r--r--chromium/media/audio/android/audio_track_output_stream.h67
-rw-r--r--chromium/media/audio/android/opensles_input.cc5
-rw-r--r--chromium/media/audio/android/opensles_input.h2
-rw-r--r--chromium/media/audio/android/opensles_output.cc46
-rw-r--r--chromium/media/audio/android/opensles_output.h4
-rw-r--r--chromium/media/audio/audio_debug_recording_helper.h3
-rw-r--r--chromium/media/audio/audio_input_controller.cc9
-rw-r--r--chromium/media/audio/audio_input_controller.h2
-rw-r--r--chromium/media/audio/audio_input_controller_unittest.cc2
-rw-r--r--chromium/media/audio/audio_input_device.cc9
-rw-r--r--chromium/media/audio/audio_input_device.h7
-rw-r--r--chromium/media/audio/audio_input_unittest.cc7
-rw-r--r--chromium/media/audio/audio_io.h8
-rw-r--r--chromium/media/audio/audio_low_latency_input_output_unittest.cc4
-rw-r--r--chromium/media/audio/audio_manager.cc5
-rw-r--r--chromium/media/audio/audio_manager.h8
-rw-r--r--chromium/media/audio/audio_manager_base.cc19
-rw-r--r--chromium/media/audio/audio_manager_base.h1
-rw-r--r--chromium/media/audio/audio_output_controller.cc34
-rw-r--r--chromium/media/audio/audio_output_controller.h20
-rw-r--r--chromium/media/audio/audio_output_controller_unittest.cc29
-rw-r--r--chromium/media/audio/audio_output_device.cc15
-rw-r--r--chromium/media/audio/audio_output_device.h11
-rw-r--r--chromium/media/audio/audio_output_device_unittest.cc51
-rw-r--r--chromium/media/audio/audio_output_proxy_unittest.cc1
-rw-r--r--chromium/media/audio/audio_output_resampler.cc34
-rw-r--r--chromium/media/audio/audio_output_stream_sink.h2
-rw-r--r--chromium/media/audio/audio_system.h27
-rw-r--r--chromium/media/audio/audio_system_impl.cc20
-rw-r--r--chromium/media/audio/audio_system_impl.h27
-rw-r--r--chromium/media/audio/audio_system_impl_unittest.cc20
-rw-r--r--chromium/media/audio/clockless_audio_sink.cc10
-rw-r--r--chromium/media/audio/clockless_audio_sink.h6
-rw-r--r--chromium/media/audio/cras/audio_manager_cras.cc293
-rw-r--r--chromium/media/audio/cras/audio_manager_cras.h34
-rw-r--r--chromium/media/audio/cras/cras_input.cc28
-rw-r--r--chromium/media/audio/cras/cras_input_unittest.cc12
-rw-r--r--chromium/media/audio/cras/cras_unified_unittest.cc7
-rw-r--r--chromium/media/audio/fake_audio_input_stream.cc2
-rw-r--r--chromium/media/audio/fake_audio_input_stream.h2
-rw-r--r--chromium/media/audio/fake_audio_log_factory.h3
-rw-r--r--chromium/media/audio/fake_audio_output_stream.h2
-rw-r--r--chromium/media/audio/fake_audio_worker.cc158
-rw-r--r--chromium/media/audio/fake_audio_worker.h54
-rw-r--r--chromium/media/audio/fake_audio_worker_unittest.cc149
-rw-r--r--chromium/media/audio/fuchsia/audio_manager_fuchsia.cc4
-rw-r--r--chromium/media/audio/fuchsia/audio_manager_fuchsia.h1
-rw-r--r--chromium/media/audio/mac/audio_input_mac.cc18
-rw-r--r--chromium/media/audio/mac/audio_low_latency_input_mac.cc47
-rw-r--r--chromium/media/audio/mac/audio_low_latency_input_mac.h10
-rw-r--r--chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc12
-rw-r--r--chromium/media/audio/mac/audio_manager_mac.cc25
-rw-r--r--chromium/media/audio/mac/audio_manager_mac.h2
-rw-r--r--chromium/media/audio/mac/coreaudio_dispatch_override.cc147
-rw-r--r--chromium/media/audio/mac/coreaudio_dispatch_override.h29
-rw-r--r--chromium/media/audio/mock_audio_manager.cc3
-rw-r--r--chromium/media/audio/mock_audio_manager.h2
-rw-r--r--chromium/media/audio/null_audio_sink.cc2
-rw-r--r--chromium/media/audio/null_audio_sink.h3
-rw-r--r--chromium/media/audio/pulse/audio_manager_pulse.cc9
-rw-r--r--chromium/media/audio/pulse/audio_manager_pulse.h1
-rw-r--r--chromium/media/audio/pulse/pulse_input.cc22
-rw-r--r--chromium/media/audio/pulse/pulse_util.cc9
-rw-r--r--chromium/media/audio/pulse/pulse_util.h4
-rw-r--r--chromium/media/audio/sample_rates.cc57
-rw-r--r--chromium/media/audio/sample_rates.h38
-rw-r--r--chromium/media/audio/virtual_audio_input_stream.cc2
-rw-r--r--chromium/media/audio/virtual_audio_input_stream.h2
-rw-r--r--chromium/media/audio/virtual_audio_input_stream_unittest.cc7
-rw-r--r--chromium/media/audio/win/audio_low_latency_input_win.cc78
-rw-r--r--chromium/media/audio/win/audio_low_latency_input_win.h8
-rw-r--r--chromium/media/audio/win/audio_low_latency_input_win_unittest.cc9
-rw-r--r--chromium/media/audio/win/audio_manager_win.cc20
-rw-r--r--chromium/media/audio/win/audio_manager_win.h1
-rw-r--r--chromium/media/audio/win/audio_output_win_unittest.cc5
-rw-r--r--chromium/media/audio/win/core_audio_util_win.cc7
87 files changed, 1149 insertions, 1067 deletions
diff --git a/chromium/media/audio/BUILD.gn b/chromium/media/audio/BUILD.gn
index bc999b57ef4..7ee82dfab0a 100644
--- a/chromium/media/audio/BUILD.gn
+++ b/chromium/media/audio/BUILD.gn
@@ -20,7 +20,6 @@ if (!link_pulseaudio) {
]
stubs_filename_root = "pulse_stubs"
- # TODO(ajwong): these need to be included in the pulse build.
outputs = [
"$target_gen_dir/pulse/$stubs_filename_root.cc",
"$target_gen_dir/pulse/$stubs_filename_root.h",
@@ -51,7 +50,19 @@ config("platform_config") {
}
source_set("audio") {
- visibility = [ "//media/*" ]
+ # Do not expand the visibility here without double-checking with OWNERS, this
+ # is a roll-up target which is part of the //media component. Most other DEPs
+ # should be using //media and not directly DEP this roll-up target.
+ visibility = [
+ "//media",
+
+ # TODO(dalecurtis): CoreAudioUtil::IsCoreAudioSupported() should probably
+ # move into media/base/win.
+ "//media/device_monitors",
+
+ # TODO(dalecurtis): Move android audio pieces into //media/audio.
+ "//media/base/android",
+ ]
sources = [
"agc_audio_stream.h",
"audio_debug_file_writer.cc",
@@ -117,12 +128,8 @@ source_set("audio") {
"fake_audio_manager.h",
"fake_audio_output_stream.cc",
"fake_audio_output_stream.h",
- "fake_audio_worker.cc",
- "fake_audio_worker.h",
"null_audio_sink.cc",
"null_audio_sink.h",
- "sample_rates.cc",
- "sample_rates.h",
"scoped_task_runner_observer.cc",
"scoped_task_runner_observer.h",
"simple_sources.cc",
@@ -142,15 +149,13 @@ source_set("audio") {
]
deps = [
"//base",
- "//media:shared_memory_support",
"//media/base",
"//url",
]
libs = []
configs += [
":platform_config",
- "//media:media_config",
- "//media:media_implementation",
+ "//media:subcomponent_config",
]
if (is_mac) {
@@ -165,6 +170,8 @@ source_set("audio") {
"mac/audio_low_latency_input_mac.h",
"mac/audio_manager_mac.cc",
"mac/audio_manager_mac.h",
+ "mac/coreaudio_dispatch_override.cc",
+ "mac/coreaudio_dispatch_override.h",
"mac/scoped_audio_unit.cc",
"mac/scoped_audio_unit.h",
]
@@ -209,6 +216,8 @@ source_set("audio") {
"android/audio_manager_android.h",
"android/audio_record_input.cc",
"android/audio_record_input.h",
+ "android/audio_track_output_stream.cc",
+ "android/audio_track_output_stream.h",
"android/muteable_audio_output_stream.h",
"android/opensles_input.cc",
"android/opensles_input.h",
@@ -218,6 +227,7 @@ source_set("audio") {
"android/opensles_util.h",
"android/opensles_wrapper.cc",
]
+
deps += [ "//media/base/android:media_jni_headers" ]
}
@@ -269,7 +279,6 @@ source_set("audio") {
if (link_pulseaudio) {
configs += [ ":libpulse" ]
} else {
- # TODO(ajwong): Technically, this dl should go in the action.
libs += [ "dl" ]
deps += [ ":pulse_generate_stubs" ]
sources += get_target_outputs(":pulse_generate_stubs")
@@ -298,7 +307,10 @@ if (use_pulseaudio && link_pulseaudio) {
}
}
+# Note: This is a roll-up only target; do not expand the visibility. DEPS should
+# depend on the //media:test_support target instead.
static_library("test_support") {
+ visibility = [ "//media:test_support" ]
testonly = true
sources = [
"audio_device_info_accessor_for_tests.cc",
@@ -320,7 +332,11 @@ static_library("test_support") {
]
deps = [
"//base",
- "//media",
+
+ # Do not add any other //media deps except this; it will automatically pull
+ # a dep on //media which is required to ensure test_support targets all use
+ # the same //media component and not build a target's sources individually.
+ "//media/base:test_support",
"//testing/gmock",
"//testing/gtest",
]
@@ -341,17 +357,15 @@ source_set("unit_tests") {
"audio_output_proxy_unittest.cc",
"audio_power_monitor_unittest.cc",
"audio_system_impl_unittest.cc",
- "fake_audio_worker_unittest.cc",
"simple_sources_unittest.cc",
"virtual_audio_input_stream_unittest.cc",
"virtual_audio_output_stream_unittest.cc",
]
+
deps = [
- ":test_support",
"//base",
"//base/test:test_support",
- "//media",
- "//media/base:test_support",
+ "//media:test_support",
"//testing/gmock",
"//testing/gtest",
"//url",
diff --git a/chromium/media/audio/OWNERS b/chromium/media/audio/OWNERS
index 6485207e45d..9bb055240f5 100644
--- a/chromium/media/audio/OWNERS
+++ b/chromium/media/audio/OWNERS
@@ -1,4 +1,6 @@
tommi@chromium.org
+olka@chromium.org
+maxmorin@chromium.org
# Windows
henrika@chromium.org
diff --git a/chromium/media/audio/alsa/alsa_input.cc b/chromium/media/audio/alsa/alsa_input.cc
index be414868ad9..6d756c8ec24 100644
--- a/chromium/media/audio/alsa/alsa_input.cc
+++ b/chromium/media/audio/alsa/alsa_input.cc
@@ -160,6 +160,8 @@ bool AlsaPcmInputStream::Recover(int original_error) {
snd_pcm_sframes_t AlsaPcmInputStream::GetCurrentDelay() {
snd_pcm_sframes_t delay = -1;
+ // TODO(dalecurtis): This should probably use snd_pcm_htimestamp() so that we
+ // can have |capture_time| directly instead of computing it as Now() - delay.
int error = wrapper_->PcmDelay(device_handle_, &delay);
if (error < 0)
Recover(error);
@@ -199,25 +201,26 @@ void AlsaPcmInputStream::ReadAudio() {
return;
}
- int num_buffers = frames / params_.frames_per_buffer();
- uint32_t hardware_delay_bytes =
- static_cast<uint32_t>(GetCurrentDelay() * params_.GetBytesPerFrame());
- double normalized_volume = 0.0;
-
// Update the AGC volume level once every second. Note that, |volume| is
// also updated each time SetVolume() is called through IPC by the
// render-side AGC.
+ double normalized_volume = 0.0;
GetAgcVolume(&normalized_volume);
+ int num_buffers = frames / params_.frames_per_buffer();
while (num_buffers--) {
int frames_read = wrapper_->PcmReadi(device_handle_, audio_buffer_.get(),
params_.frames_per_buffer());
if (frames_read == params_.frames_per_buffer()) {
- audio_bus_->FromInterleaved(audio_buffer_.get(),
- audio_bus_->frames(),
+ audio_bus_->FromInterleaved(audio_buffer_.get(), audio_bus_->frames(),
params_.bits_per_sample() / 8);
- callback_->OnData(
- this, audio_bus_.get(), hardware_delay_bytes, normalized_volume);
+
+ base::TimeDelta hardware_delay = base::TimeDelta::FromSecondsD(
+ GetCurrentDelay() / static_cast<double>(params_.sample_rate()));
+
+ callback_->OnData(this, audio_bus_.get(),
+ base::TimeTicks::Now() - hardware_delay,
+ normalized_volume);
} else {
LOG(WARNING) << "PcmReadi returning less than expected frames: "
<< frames_read << " vs. " << params_.frames_per_buffer()
diff --git a/chromium/media/audio/alsa/audio_manager_alsa.cc b/chromium/media/audio/alsa/audio_manager_alsa.cc
index 33fc0b2ddb9..5f5bc6d7e64 100644
--- a/chromium/media/audio/alsa/audio_manager_alsa.cc
+++ b/chromium/media/audio/alsa/audio_manager_alsa.cc
@@ -7,14 +7,10 @@
#include <stddef.h>
#include "base/command_line.h"
-#include "base/environment.h"
-#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/free_deleter.h"
#include "base/metrics/histogram.h"
-#include "base/nix/xdg_util.h"
-#include "base/process/launch.h"
#include "base/stl_util.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/audio_output_dispatcher.h"
@@ -44,40 +40,10 @@ static const int kDefaultSampleRate = 48000;
// real devices, we remove them from the list to avoiding duplicate counting.
// In addition, note that we support no more than 2 channels for recording,
// hence surround devices are not stored in the list.
-static const char* kInvalidAudioInputDevices[] = {
- "default",
- "dmix",
- "null",
- "pulse",
- "surround",
+static const char* const kInvalidAudioInputDevices[] = {
+ "default", "dmix", "null", "pulse", "surround",
};
-// static
-void AudioManagerAlsa::ShowLinuxAudioInputSettings() {
- std::unique_ptr<base::Environment> env(base::Environment::Create());
- base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
- switch (base::nix::GetDesktopEnvironment(env.get())) {
- case base::nix::DESKTOP_ENVIRONMENT_GNOME:
- command_line.SetProgram(base::FilePath("gnome-volume-control"));
- break;
- case base::nix::DESKTOP_ENVIRONMENT_KDE3:
- case base::nix::DESKTOP_ENVIRONMENT_KDE4:
- case base::nix::DESKTOP_ENVIRONMENT_KDE5:
- command_line.SetProgram(base::FilePath("kmix"));
- break;
- case base::nix::DESKTOP_ENVIRONMENT_UNITY:
- command_line.SetProgram(base::FilePath("gnome-control-center"));
- command_line.AppendArg("sound");
- command_line.AppendArg("input");
- break;
- default:
- LOG(ERROR) << "Failed to show audio input settings: we don't know "
- << "what command to use for your desktop environment.";
- return;
- }
- base::LaunchProcess(command_line, base::LaunchOptions());
-}
-
AudioManagerAlsa::AudioManagerAlsa(std::unique_ptr<AudioThread> audio_thread,
AudioLogFactory* audio_log_factory)
: AudioManagerBase(std::move(audio_thread), audio_log_factory),
@@ -95,10 +61,6 @@ bool AudioManagerAlsa::HasAudioInputDevices() {
return HasAnyAlsaAudioDevice(kStreamCapture);
}
-void AudioManagerAlsa::ShowAudioInputSettings() {
- ShowLinuxAudioInputSettings();
-}
-
void AudioManagerAlsa::GetAudioInputDeviceNames(
AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
@@ -219,17 +181,16 @@ bool AudioManagerAlsa::IsAlsaDeviceAvailable(
return false;
}
return true;
- } else {
- DCHECK_EQ(kStreamPlayback, type);
- // We prefer the device type that maps straight to hardware but
- // goes through software conversion if needed (e.g. incompatible
- // sample rate).
- // TODO(joi): Should we prefer "hw" instead?
- static const char kDeviceTypeDesired[] = "plughw";
- return strncmp(kDeviceTypeDesired,
- device_name,
- arraysize(kDeviceTypeDesired) - 1) == 0;
}
+
+ DCHECK_EQ(kStreamPlayback, type);
+ // We prefer the device type that maps straight to hardware but
+ // goes through software conversion if needed (e.g. incompatible
+ // sample rate).
+ // TODO(joi): Should we prefer "hw" instead?
+ static const char kDeviceTypeDesired[] = "plughw";
+ return strncmp(kDeviceTypeDesired, device_name,
+ arraysize(kDeviceTypeDesired) - 1) == 0;
}
// static
diff --git a/chromium/media/audio/alsa/audio_manager_alsa.h b/chromium/media/audio/alsa/audio_manager_alsa.h
index a5c57dcfc3b..ab146785c55 100644
--- a/chromium/media/audio/alsa/audio_manager_alsa.h
+++ b/chromium/media/audio/alsa/audio_manager_alsa.h
@@ -24,12 +24,9 @@ class MEDIA_EXPORT AudioManagerAlsa : public AudioManagerBase {
AudioLogFactory* audio_log_factory);
~AudioManagerAlsa() override;
- static void ShowLinuxAudioInputSettings();
-
// Implementation of AudioManager.
bool HasAudioOutputDevices() override;
bool HasAudioInputDevices() override;
- void ShowAudioInputSettings() override;
void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
AudioParameters GetInputStreamParameters(
diff --git a/chromium/media/audio/android/audio_android_unittest.cc b/chromium/media/audio/android/audio_android_unittest.cc
index cae9490c289..7005dc82498 100644
--- a/chromium/media/audio/android/audio_android_unittest.cc
+++ b/chromium/media/audio/android/audio_android_unittest.cc
@@ -163,7 +163,7 @@ class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
MOCK_METHOD4(OnData,
void(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume));
MOCK_METHOD1(OnError, void(AudioInputStream* stream));
};
@@ -277,7 +277,7 @@ class FileAudioSink : public AudioInputStream::AudioInputCallback {
// AudioInputStream::AudioInputCallback implementation.
void OnData(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
const int num_samples = src->frames() * src->channels();
std::unique_ptr<int16_t> interleaved(new int16_t[num_samples]);
@@ -325,7 +325,7 @@ class FullDuplexAudioSinkSource
// AudioInputStream::AudioInputCallback implementation
void OnData(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
const base::TimeTicks now_time = base::TimeTicks::Now();
const int diff = (now_time - previous_time_).InMilliseconds();
diff --git a/chromium/media/audio/android/audio_manager_android.cc b/chromium/media/audio/android/audio_manager_android.cc
index 17567885331..61abb0cc283 100644
--- a/chromium/media/audio/android/audio_manager_android.cc
+++ b/chromium/media/audio/android/audio_manager_android.cc
@@ -15,6 +15,7 @@
#include "base/strings/string_number_conversions.h"
#include "jni/AudioManagerAndroid_jni.h"
#include "media/audio/android/audio_record_input.h"
+#include "media/audio/android/audio_track_output_stream.h"
#include "media/audio/android/opensles_input.h"
#include "media/audio/android/opensles_output.h"
#include "media/audio/audio_device_description.h"
@@ -28,6 +29,7 @@ using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
+using base::android::JavaRef;
using base::android::ScopedJavaLocalRef;
namespace media {
@@ -239,9 +241,8 @@ AudioOutputStream* AudioManagerAndroid::MakeBitstreamOutputStream(
const AudioParameters& params,
const std::string& device_id,
const LogCallback& log_callback) {
- // TODO(tsunghung): add output stream for audio bitstream formats.
- NOTREACHED();
- return nullptr;
+ DCHECK(params.IsBitstreamFormat());
+ return new AudioTrackOutputStream(this, params);
}
AudioInputStream* AudioManagerAndroid::MakeLinearInputStream(
@@ -284,8 +285,9 @@ AudioInputStream* AudioManagerAndroid::MakeLowLatencyInputStream(
}
// static
-bool AudioManagerAndroid::RegisterAudioManager(JNIEnv* env) {
- return RegisterNativesImpl(env);
+bool AudioManagerAndroid::SupportsPerformanceModeForOutput() {
+ return base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_NOUGAT_MR1;
}
void AudioManagerAndroid::SetMute(JNIEnv* env,
@@ -339,8 +341,16 @@ AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
channel_layout = input_params.channel_layout();
}
- buffer_size = GetOptimalOutputFrameSize(
- sample_rate, ChannelLayoutToChannelCount(channel_layout));
+ // For high latency playback on supported platforms, pass through the
+ // requested buffer size; this provides significant power savings (~25%) and
+ // reduces the potential for glitches under load.
+ if (SupportsPerformanceModeForOutput() &&
+ input_params.latency_tag() == AudioLatency::LATENCY_PLAYBACK) {
+ buffer_size = input_params.frames_per_buffer();
+ } else {
+ buffer_size = GetOptimalOutputFrameSize(
+ sample_rate, ChannelLayoutToChannelCount(channel_layout));
+ }
}
int user_buffer_size = GetUserBufferSize();
@@ -355,7 +365,7 @@ bool AudioManagerAndroid::HasNoAudioInputStreams() {
return input_stream_count() == 0;
}
-jobject AudioManagerAndroid::GetJavaAudioManager() {
+const JavaRef<jobject>& AudioManagerAndroid::GetJavaAudioManager() {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
if (j_audio_manager_.is_null()) {
// Create the Android audio manager on the audio thread.
@@ -369,7 +379,7 @@ jobject AudioManagerAndroid::GetJavaAudioManager() {
Java_AudioManagerAndroid_init(base::android::AttachCurrentThread(),
j_audio_manager_);
}
- return j_audio_manager_.obj();
+ return j_audio_manager_;
}
void AudioManagerAndroid::SetCommunicationAudioModeOn(bool on) {
diff --git a/chromium/media/audio/android/audio_manager_android.h b/chromium/media/audio/android/audio_manager_android.h
index c65b6340b5d..5075ed514f1 100644
--- a/chromium/media/audio/android/audio_manager_android.h
+++ b/chromium/media/audio/android/audio_manager_android.h
@@ -67,7 +67,10 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
const std::string& device_id,
const LogCallback& log_callback) override;
- static bool RegisterAudioManager(JNIEnv* env);
+ // Indicates if there's support for the OpenSLES performance mode keys. See
+ // OpenSLESOutputStream for specific details. Essentially this allows for low
+ // power audio when large buffer sizes can be used.
+ static bool SupportsPerformanceModeForOutput();
void SetMute(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
@@ -85,7 +88,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
const AudioParameters& input_params) override;
private:
- jobject GetJavaAudioManager();
+ const base::android::JavaRef<jobject>& GetJavaAudioManager();
bool HasNoAudioInputStreams();
void SetCommunicationAudioModeOn(bool on);
bool SetAudioDevice(const std::string& device_id);
diff --git a/chromium/media/audio/android/audio_record_input.cc b/chromium/media/audio/android/audio_record_input.cc
index 8e436ff328b..521676a8c04 100644
--- a/chromium/media/audio/android/audio_record_input.cc
+++ b/chromium/media/audio/android/audio_record_input.cc
@@ -48,23 +48,21 @@ void AudioRecordInputStream::CacheDirectBufferAddress(
static_cast<uint8_t*>(env->GetDirectBufferAddress(byte_buffer));
}
-// static
-bool AudioRecordInputStream::RegisterAudioRecordInput(JNIEnv* env) {
- return RegisterNativesImpl(env);
-}
-
void AudioRecordInputStream::OnData(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jint size,
- jint hardware_delay_bytes) {
+ jint hardware_delay_ms) {
DCHECK(direct_buffer_address_);
DCHECK_EQ(size,
audio_bus_->frames() * audio_bus_->channels() * bytes_per_sample_);
// Passing zero as the volume parameter indicates there is no access to a
// hardware volume slider.
- audio_bus_->FromInterleaved(
- direct_buffer_address_, audio_bus_->frames(), bytes_per_sample_);
- callback_->OnData(this, audio_bus_.get(), hardware_delay_bytes, 0.0);
+ audio_bus_->FromInterleaved(direct_buffer_address_, audio_bus_->frames(),
+ bytes_per_sample_);
+ callback_->OnData(this, audio_bus_.get(),
+ base::TimeTicks::Now() -
+ base::TimeDelta::FromMilliseconds(hardware_delay_ms),
+ 0.0);
}
bool AudioRecordInputStream::Open() {
diff --git a/chromium/media/audio/android/audio_record_input.h b/chromium/media/audio/android/audio_record_input.h
index 1e9f0ebd087..f1cf02ee12a 100644
--- a/chromium/media/audio/android/audio_record_input.h
+++ b/chromium/media/audio/android/audio_record_input.h
@@ -44,13 +44,11 @@ class MEDIA_EXPORT AudioRecordInputStream : public AudioInputStream {
bool GetAutomaticGainControl() override;
bool IsMuted() override;
- static bool RegisterAudioRecordInput(JNIEnv* env);
-
// Called from Java when data is available.
void OnData(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
jint size,
- jint hardware_delay_bytes);
+ jint hardware_delay_ms);
// Called from Java so that we can cache the address of the Java-managed
// |byte_buffer| in |direct_buffer_address_|.
diff --git a/chromium/media/audio/android/audio_track_output_stream.cc b/chromium/media/audio/android/audio_track_output_stream.cc
new file mode 100644
index 00000000000..07f5cd5153b
--- /dev/null
+++ b/chromium/media/audio/android/audio_track_output_stream.cc
@@ -0,0 +1,181 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/android/audio_track_output_stream.h"
+
+#include <cmath>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/time/default_tick_clock.h"
+#include "jni/AudioTrackOutputStream_jni.h"
+#include "media/audio/audio_manager_base.h"
+#include "media/base/audio_sample_types.h"
+#include "media/base/audio_timestamp_helper.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+
+namespace media {
+
+// Android audio format. For more information, please see:
+// https://developer.android.com/reference/android/media/AudioFormat.html
+enum {
+ kEncodingPcm16bit = 2, // ENCODING_PCM_16BIT
+ kEncodingAc3 = 5, // ENCODING_AC3
+ kEncodingEac3 = 6, // ENCODING_E_AC3
+};
+
+AudioTrackOutputStream::AudioTrackOutputStream(AudioManagerBase* manager,
+ const AudioParameters& params)
+ : params_(params),
+ audio_manager_(manager),
+ tick_clock_(new base::DefaultTickClock()) {
+ if (!params_.IsBitstreamFormat()) {
+ audio_bus_ = AudioBus::Create(params_);
+ }
+}
+
+AudioTrackOutputStream::~AudioTrackOutputStream() {
+ DCHECK(!callback_);
+}
+
+bool AudioTrackOutputStream::Open() {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ JNIEnv* env = AttachCurrentThread();
+ j_audio_output_stream_.Reset(Java_AudioTrackOutputStream_create(env));
+
+ int format = kEncodingPcm16bit;
+ if (params_.IsBitstreamFormat()) {
+ if (params_.format() == AudioParameters::AUDIO_BITSTREAM_AC3) {
+ format = kEncodingAc3;
+ } else if (params_.format() == AudioParameters::AUDIO_BITSTREAM_EAC3) {
+ format = kEncodingEac3;
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ return Java_AudioTrackOutputStream_open(env, j_audio_output_stream_,
+ params_.channels(),
+ params_.sample_rate(), format);
+}
+
+void AudioTrackOutputStream::Start(AudioSourceCallback* callback) {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ callback_ = callback;
+ Java_AudioTrackOutputStream_start(AttachCurrentThread(),
+ j_audio_output_stream_,
+ reinterpret_cast<intptr_t>(this));
+}
+
+void AudioTrackOutputStream::Stop() {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ Java_AudioTrackOutputStream_stop(AttachCurrentThread(),
+ j_audio_output_stream_);
+ callback_ = nullptr;
+}
+
+void AudioTrackOutputStream::Close() {
+ DCHECK(!callback_);
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+
+ Java_AudioTrackOutputStream_close(AttachCurrentThread(),
+ j_audio_output_stream_);
+ audio_manager_->ReleaseOutputStream(this);
+}
+
+void AudioTrackOutputStream::SetMute(bool muted) {
+ if (params_.IsBitstreamFormat() && muted) {
+ LOG(WARNING)
+ << "Mute is not supported for compressed audio bitstream formats.";
+ return;
+ }
+
+ if (muted_ == muted)
+ return;
+
+ muted_ = muted;
+ Java_AudioTrackOutputStream_setVolume(
+ AttachCurrentThread(), j_audio_output_stream_, muted_ ? 0.0 : volume_);
+}
+
+void AudioTrackOutputStream::SetVolume(double volume) {
+ if (params_.IsBitstreamFormat()) {
+ LOG(WARNING) << "Volume change is not supported for compressed audio "
+ "bitstream formats.";
+ return;
+ }
+
+ // Track |volume_| since AudioTrack uses a scaled value.
+ volume_ = volume;
+ if (muted_)
+ return;
+
+ Java_AudioTrackOutputStream_setVolume(AttachCurrentThread(),
+ j_audio_output_stream_, volume);
+};
+
+void AudioTrackOutputStream::GetVolume(double* volume) {
+ *volume = volume_;
+};
+
+// AudioOutputStream::SourceCallback implementation methods called from Java.
+ScopedJavaLocalRef<jobject> AudioTrackOutputStream::OnMoreData(
+ JNIEnv* env,
+ jobject obj,
+ jobject audio_data,
+ jlong delay_in_frame) {
+ DCHECK(callback_);
+
+ base::TimeDelta delay =
+ AudioTimestampHelper::FramesToTime(delay_in_frame, params_.sample_rate());
+
+ void* native_buffer = env->GetDirectBufferAddress(audio_data);
+
+ if (params_.IsBitstreamFormat()) {
+ // For bitstream formats, use the direct buffer memory to avoid additional
+ // memory copy.
+ std::unique_ptr<AudioBus> audio_bus(
+ AudioBus::WrapMemory(params_, native_buffer));
+ audio_bus->set_is_bitstream_format(true);
+
+ callback_->OnMoreData(delay, tick_clock_->NowTicks(), 0, audio_bus.get());
+
+ if (audio_bus->GetBitstreamDataSize() <= 0)
+ return nullptr;
+
+ return Java_AudioTrackOutputStream_createAudioBufferInfo(
+ env, j_audio_output_stream_, audio_bus->GetBitstreamFrames(),
+ audio_bus->GetBitstreamDataSize());
+ }
+
+ // For PCM format, we need extra memory to convert planar float32 into
+ // interleaved int16.
+
+ callback_->OnMoreData(delay, tick_clock_->NowTicks(), 0, audio_bus_.get());
+
+ int16_t* native_bus = reinterpret_cast<int16_t*>(native_buffer);
+ audio_bus_->ToInterleaved<SignedInt16SampleTypeTraits>(audio_bus_->frames(),
+ native_bus);
+
+ return Java_AudioTrackOutputStream_createAudioBufferInfo(
+ env, j_audio_output_stream_, audio_bus_->frames(),
+ sizeof(*native_bus) * audio_bus_->channels() * audio_bus_->frames());
+}
+
+void AudioTrackOutputStream::OnError(JNIEnv* env, jobject obj) {
+ DCHECK(callback_);
+ callback_->OnError();
+}
+
+jlong AudioTrackOutputStream::GetAddress(JNIEnv* env,
+ jobject obj,
+ jobject byte_buffer) {
+ return reinterpret_cast<jlong>(env->GetDirectBufferAddress(byte_buffer));
+}
+
+} // namespace media
diff --git a/chromium/media/audio/android/audio_track_output_stream.h b/chromium/media/audio/android/audio_track_output_stream.h
new file mode 100644
index 00000000000..1b01a687d46
--- /dev/null
+++ b/chromium/media/audio/android/audio_track_output_stream.h
@@ -0,0 +1,67 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_AUDIO_ANDROID_AUDIO_TRACK_OUTPUT_STREAM_H_
+#define MEDIA_AUDIO_ANDROID_AUDIO_TRACK_OUTPUT_STREAM_H_
+
+#include <memory>
+
+#include "base/android/jni_android.h"
+#include "base/time/tick_clock.h"
+#include "media/audio/android/muteable_audio_output_stream.h"
+#include "media/base/audio_parameters.h"
+
+namespace media {
+
+class AudioManagerBase;
+
+// A MuteableAudioOutputStream implementation based on the Android AudioTrack
+// API.
+class MEDIA_EXPORT AudioTrackOutputStream : public MuteableAudioOutputStream {
+ public:
+ AudioTrackOutputStream(AudioManagerBase* manager,
+ const AudioParameters& params);
+ ~AudioTrackOutputStream() override;
+
+ // AudioOutputStream implementation.
+ bool Open() override;
+ void Start(AudioSourceCallback* callback) override;
+ void Stop() override;
+ void SetVolume(double volume) override;
+ void GetVolume(double* volume) override;
+ void Close() override;
+
+ // MuteableAudioOutputStream implementation.
+ void SetMute(bool muted) override;
+
+ // AudioOutputStream::SourceCallback implementation methods called from Java.
+ base::android::ScopedJavaLocalRef<jobject> OnMoreData(JNIEnv* env,
+ jobject obj,
+ jobject audio_data,
+ jlong delay);
+ void OnError(JNIEnv* env, jobject obj);
+ jlong GetAddress(JNIEnv* env, jobject obj, jobject byte_buffer);
+
+ private:
+ const AudioParameters params_;
+
+ AudioManagerBase* audio_manager_;
+ AudioSourceCallback* callback_ = nullptr;
+ bool muted_ = false;
+ double volume_ = 1.0;
+
+ // Extra buffer for PCM format.
+ std::unique_ptr<AudioBus> audio_bus_;
+
+ std::unique_ptr<base::TickClock> tick_clock_;
+
+ // Java AudioTrackOutputStream instance.
+ base::android::ScopedJavaGlobalRef<jobject> j_audio_output_stream_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioTrackOutputStream);
+};
+
+} // namespace media
+
+#endif // MEDIA_AUDIO_ANDROID_AUDIO_TRACK_OUTPUT_STREAM_H_
diff --git a/chromium/media/audio/android/opensles_input.cc b/chromium/media/audio/android/opensles_input.cc
index 748a9cca802..bccda08be62 100644
--- a/chromium/media/audio/android/opensles_input.cc
+++ b/chromium/media/audio/android/opensles_input.cc
@@ -42,6 +42,8 @@ OpenSLESInputStream::OpenSLESInputStream(AudioManagerAndroid* audio_manager,
format_.channelMask = ChannelCountToSLESChannelMask(params.channels());
buffer_size_bytes_ = params.GetBytesPerBuffer();
+ hardware_delay_ = base::TimeDelta::FromSecondsD(
+ params.frames_per_buffer() / static_cast<double>(params.sample_rate()));
memset(&audio_data_, 0, sizeof(audio_data_));
}
@@ -306,7 +308,8 @@ void OpenSLESInputStream::ReadBufferQueue() {
// TODO(henrika): Investigate if it is possible to get an accurate
// delay estimation.
- callback_->OnData(this, audio_bus_.get(), buffer_size_bytes_, 0.0);
+ callback_->OnData(this, audio_bus_.get(),
+ base::TimeTicks::Now() - hardware_delay_, 0.0);
// Done with this buffer. Send it to device for recording.
SLresult err =
diff --git a/chromium/media/audio/android/opensles_input.h b/chromium/media/audio/android/opensles_input.h
index 7a99cd79021..f7385dea8de 100644
--- a/chromium/media/audio/android/opensles_input.h
+++ b/chromium/media/audio/android/opensles_input.h
@@ -100,6 +100,8 @@ class OpenSLESInputStream : public AudioInputStream {
bool started_;
+ base::TimeDelta hardware_delay_;
+
std::unique_ptr<media::AudioBus> audio_bus_;
DISALLOW_COPY_AND_ASSIGN(OpenSLESInputStream);
diff --git a/chromium/media/audio/android/opensles_output.cc b/chromium/media/audio/android/opensles_output.cc
index 5893de36904..81a02dbdbf8 100644
--- a/chromium/media/audio/android/opensles_output.cc
+++ b/chromium/media/audio/android/opensles_output.cc
@@ -23,6 +23,28 @@
} \
} while (0)
+// On N MR1+ we want to use high buffer sizes for power saving. Per Android
+// audio team, this should be in N MR1+ SDK, but it's not, so use a defined()
+// check instead of __API_LEVEL__ check.
+#if !defined(SL_ANDROID_KEY_PERFORMANCE_MODE)
+#define SL_ANDROID_KEY_PERFORMANCE_MODE \
+ ((const SLchar*)"androidPerformanceMode")
+
+// No specific performance requirement. Allows HW and SW pre/post processing.
+#define SL_ANDROID_PERFORMANCE_NONE ((SLuint32)0x00000000)
+
+// Priority given to latency. No HW or software pre/post processing. This is the
+// default if no performance mode is specified.
+#define SL_ANDROID_PERFORMANCE_LATENCY ((SLuint32)0x00000001)
+
+// Priority given to latency while still allowing HW pre and post processing.
+#define SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS ((SLuint32)0x00000002)
+
+// Priority given to power saving if latency is not a concern. Allows HW and SW
+// pre/post processing.
+#define SL_ANDROID_PERFORMANCE_POWER_SAVING ((SLuint32)0x00000003)
+#endif
+
namespace media {
OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
@@ -52,10 +74,18 @@ OpenSLESOutputStream::OpenSLESOutputStream(AudioManagerAndroid* manager,
buffer_size_bytes_(have_float_output_
? bytes_per_frame_ * params.frames_per_buffer()
: params.GetBytesPerBuffer()),
+ performance_mode_(SL_ANDROID_PERFORMANCE_NONE),
delay_calculator_(samples_per_second_) {
DVLOG(2) << "OpenSLESOutputStream::OpenSLESOutputStream("
<< "stream_type=" << stream_type << ")";
+ if (AudioManagerAndroid::SupportsPerformanceModeForOutput()) {
+ if (params.latency_tag() == AudioLatency::LATENCY_PLAYBACK)
+ performance_mode_ = SL_ANDROID_PERFORMANCE_POWER_SAVING;
+ else if (params.latency_tag() == AudioLatency::LATENCY_RTC)
+ performance_mode_ = SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS;
+ }
+
audio_bus_ = AudioBus::Create(params);
if (have_float_output_) {
@@ -307,12 +337,20 @@ bool OpenSLESOutputStream::CreatePlayer() {
// Set configuration using the stream type provided at construction.
LOG_ON_FAILURE_AND_RETURN(
- (*player_config)->SetConfiguration(player_config,
- SL_ANDROID_KEY_STREAM_TYPE,
- &stream_type_,
- sizeof(SLint32)),
+ (*player_config)
+ ->SetConfiguration(player_config, SL_ANDROID_KEY_STREAM_TYPE,
+ &stream_type_, sizeof(SLint32)),
false);
+ // Set configuration using the stream type provided at construction.
+ if (performance_mode_ > SL_ANDROID_PERFORMANCE_NONE) {
+ LOG_ON_FAILURE_AND_RETURN(
+ (*player_config)
+ ->SetConfiguration(player_config, SL_ANDROID_KEY_PERFORMANCE_MODE,
+ &performance_mode_, sizeof(SLuint32)),
+ false);
+ }
+
// Realize the player object in synchronous mode.
LOG_ON_FAILURE_AND_RETURN(
player_object_->Realize(player_object_.Get(), SL_BOOLEAN_FALSE), false);
diff --git a/chromium/media/audio/android/opensles_output.h b/chromium/media/audio/android/opensles_output.h
index 17a91aaa524..db9b75e7fa5 100644
--- a/chromium/media/audio/android/opensles_output.h
+++ b/chromium/media/audio/android/opensles_output.h
@@ -147,6 +147,10 @@ class OpenSLESOutputStream : public MuteableAudioOutputStream {
int bytes_per_frame_;
size_t buffer_size_bytes_;
+ // On API level 25+ we can provide hints to OpenSLES about what type of
+ // content the stream is being used for.
+ SLuint32 performance_mode_;
+
// Used to calculate the delay value for each OnMoreData() call.
AudioTimestampHelper delay_calculator_;
diff --git a/chromium/media/audio/audio_debug_recording_helper.h b/chromium/media/audio/audio_debug_recording_helper.h
index b0f4c127d23..362b07f8ce0 100644
--- a/chromium/media/audio/audio_debug_recording_helper.h
+++ b/chromium/media/audio/audio_debug_recording_helper.h
@@ -47,8 +47,7 @@ class AudioDebugRecorder {
// soundcard thread -> control thread -> file thread,
// and with the merge we should be able to do
// soundcard thread -> file thread.
-class MEDIA_EXPORT AudioDebugRecordingHelper
- : public NON_EXPORTED_BASE(AudioDebugRecorder) {
+class MEDIA_EXPORT AudioDebugRecordingHelper : public AudioDebugRecorder {
public:
AudioDebugRecordingHelper(
const AudioParameters& params,
diff --git a/chromium/media/audio/audio_input_controller.cc b/chromium/media/audio/audio_input_controller.cc
index 5ba8ebfcd7c..13564802479 100644
--- a/chromium/media/audio/audio_input_controller.cc
+++ b/chromium/media/audio/audio_input_controller.cc
@@ -117,13 +117,13 @@ class AudioInputController::AudioCallback
private:
void OnData(AudioInputStream* stream,
const AudioBus* source,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
TRACE_EVENT0("audio", "AC::OnData");
received_callback_ = true;
- DeliverDataToSyncWriter(source, hardware_delay_bytes, volume);
+ DeliverDataToSyncWriter(source, capture_time, volume);
#if BUILDFLAG(ENABLE_WEBRTC)
controller_->debug_recording_helper_.OnData(source);
@@ -138,11 +138,10 @@ class AudioInputController::AudioCallback
}
void DeliverDataToSyncWriter(const AudioBus* source,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) {
bool key_pressed = controller_->CheckForKeyboardInput();
- controller_->sync_writer_->Write(source, volume, key_pressed,
- hardware_delay_bytes);
+ controller_->sync_writer_->Write(source, volume, key_pressed, capture_time);
// The way the two classes interact here, could be done in a nicer way.
// As is, we call the AIC here to check the audio power, return and then
diff --git a/chromium/media/audio/audio_input_controller.h b/chromium/media/audio/audio_input_controller.h
index 2b8669c2755..c6be0fdb215 100644
--- a/chromium/media/audio/audio_input_controller.h
+++ b/chromium/media/audio/audio_input_controller.h
@@ -130,7 +130,7 @@ class MEDIA_EXPORT AudioInputController
virtual void Write(const AudioBus* data,
double volume,
bool key_pressed,
- uint32_t hardware_delay_bytes) = 0;
+ base::TimeTicks capture_time) = 0;
// Close this synchronous writer.
virtual void Close() = 0;
diff --git a/chromium/media/audio/audio_input_controller_unittest.cc b/chromium/media/audio/audio_input_controller_unittest.cc
index 0b8ef9219e6..6aa45e09764 100644
--- a/chromium/media/audio/audio_input_controller_unittest.cc
+++ b/chromium/media/audio/audio_input_controller_unittest.cc
@@ -82,7 +82,7 @@ class MockSyncWriter : public AudioInputController::SyncWriter {
void(const AudioBus* data,
double volume,
bool key_pressed,
- uint32_t hardware_delay_bytes));
+ base::TimeTicks capture_time));
MOCK_METHOD0(Close, void());
};
diff --git a/chromium/media/audio/audio_input_device.cc b/chromium/media/audio/audio_input_device.cc
index 63672c1939d..37365a42eaf 100644
--- a/chromium/media/audio/audio_input_device.cc
+++ b/chromium/media/audio/audio_input_device.cc
@@ -438,9 +438,14 @@ void AudioInputDevice::AudioThreadCallback::Process(uint32_t pending_data) {
// Deliver captured data to the client in floating point format and update
// the audio delay measurement.
+ // TODO(olka, tommi): Take advantage of |capture_time| in the renderer.
+ const base::TimeTicks capture_time =
+ base::TimeTicks() +
+ base::TimeDelta::FromMicroseconds(buffer->params.capture_time);
+ DCHECK_GE(base::TimeTicks::Now(), capture_time);
+
capture_callback_->Capture(
- audio_bus,
- buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms
+ audio_bus, (base::TimeTicks::Now() - capture_time).InMilliseconds(),
buffer->params.volume, buffer->params.key_pressed);
if (++current_segment_id_ >= total_segments_)
diff --git a/chromium/media/audio/audio_input_device.h b/chromium/media/audio/audio_input_device.h
index d6562569db0..baee6632b31 100644
--- a/chromium/media/audio/audio_input_device.h
+++ b/chromium/media/audio/audio_input_device.h
@@ -76,10 +76,9 @@ namespace media {
// TODO(henrika): Add support for event handling (e.g. OnStateChanged,
// OnCaptureStopped etc.) and ensure that we can deliver these notifications
// to any clients using this class.
-class MEDIA_EXPORT AudioInputDevice
- : NON_EXPORTED_BASE(public AudioCapturerSource),
- NON_EXPORTED_BASE(public AudioInputIPCDelegate),
- NON_EXPORTED_BASE(public ScopedTaskRunnerObserver) {
+class MEDIA_EXPORT AudioInputDevice : public AudioCapturerSource,
+ public AudioInputIPCDelegate,
+ public ScopedTaskRunnerObserver {
public:
// NOTE: Clients must call Initialize() before using.
AudioInputDevice(
diff --git a/chromium/media/audio/audio_input_unittest.cc b/chromium/media/audio/audio_input_unittest.cc
index 609114d591d..232354e716e 100644
--- a/chromium/media/audio/audio_input_unittest.cc
+++ b/chromium/media/audio/audio_input_unittest.cc
@@ -27,13 +27,10 @@ namespace media {
// expected and if any error has been reported.
class TestInputCallback : public AudioInputStream::AudioInputCallback {
public:
- explicit TestInputCallback()
- : callback_count_(0),
- had_error_(0) {
- }
+ TestInputCallback() : callback_count_(0), had_error_(0) {}
void OnData(AudioInputStream* stream,
const AudioBus* source,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
++callback_count_;
}
diff --git a/chromium/media/audio/audio_io.h b/chromium/media/audio/audio_io.h
index d8d0e699a3d..7ac43cc3cf5 100644
--- a/chromium/media/audio/audio_io.h
+++ b/chromium/media/audio/audio_io.h
@@ -9,6 +9,7 @@
#include "base/time/time.h"
#include "media/base/audio_bus.h"
+#include "media/base/media_export.h"
// Low-level audio output support. To make sound there are 3 objects involved:
// - AudioSource : produces audio samples on a pull model. Implements
@@ -119,9 +120,14 @@ class MEDIA_EXPORT AudioInputStream {
// Called by the audio recorder when a full packet of audio data is
// available. This is called from a special audio thread and the
// implementation should return as soon as possible.
+ //
+ // |capture_time| is the time at which the first sample in |source| was
+ // received. The age of the audio data may be calculated by subtracting
+ // |capture_time| from base::TimeTicks::Now(). |capture_time| is always
+ // monotonically increasing.
virtual void OnData(AudioInputStream* stream,
const AudioBus* source,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) = 0;
// There was an error while recording audio. The audio sink cannot be
diff --git a/chromium/media/audio/audio_low_latency_input_output_unittest.cc b/chromium/media/audio/audio_low_latency_input_output_unittest.cc
index 69fcf3a98ca..4b2fa7f8fa7 100644
--- a/chromium/media/audio/audio_low_latency_input_output_unittest.cc
+++ b/chromium/media/audio/audio_low_latency_input_output_unittest.cc
@@ -153,7 +153,7 @@ class FullDuplexAudioSinkSource
// AudioInputStream::AudioInputCallback.
void OnData(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
base::AutoLock lock(lock_);
@@ -167,7 +167,7 @@ class FullDuplexAudioSinkSource
delay_states_[input_elements_to_write_].buffer_delay_ms =
BytesToMilliseconds(buffer_->forward_bytes());
delay_states_[input_elements_to_write_].input_delay_ms =
- BytesToMilliseconds(hardware_delay_bytes);
+ (base::TimeTicks::Now() - capture_time).InMilliseconds();
++input_elements_to_write_;
}
diff --git a/chromium/media/audio/audio_manager.cc b/chromium/media/audio/audio_manager.cc
index 54eb1bc1562..dff8b8faa59 100644
--- a/chromium/media/audio/audio_manager.cc
+++ b/chromium/media/audio/audio_manager.cc
@@ -22,13 +22,8 @@
#include "media/audio/fake_audio_log_factory.h"
#include "media/base/media_switches.h"
-#if defined(OS_MACOSX)
-#include "media/audio/mac/audio_manager_mac.h"
-#endif
-
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
-#include "media/audio/win/core_audio_util_win.h"
#endif
namespace media {
diff --git a/chromium/media/audio/audio_manager.h b/chromium/media/audio/audio_manager.h
index f91f6bd2a59..3b484cdbbf2 100644
--- a/chromium/media/audio/audio_manager.h
+++ b/chromium/media/audio/audio_manager.h
@@ -88,7 +88,7 @@ class MEDIA_EXPORT AudioManager {
// was created.
// Returns true on success but false if AudioManager could not be shutdown.
// AudioManager instance must not be deleted if shutdown failed.
- bool Shutdown();
+ virtual bool Shutdown();
// Log callback used for sending log messages from a stream to the object
// that manages the stream.
@@ -214,12 +214,6 @@ class MEDIA_EXPORT AudioManager {
// input device for this computer.
virtual base::string16 GetAudioInputDeviceModel() = 0;
- // Opens the platform default audio input settings UI.
- // Note: This could invoke an external application/preferences pane, so
- // ideally must not be called from the UI thread or other time sensitive
- // threads to avoid blocking the rest of the application.
- virtual void ShowAudioInputSettings() = 0;
-
// Appends a list of available input devices to |device_descriptions|,
// which must initially be empty. It is not guaranteed that all the
// devices in the list support all formats and sample rates for
diff --git a/chromium/media/audio/audio_manager_base.cc b/chromium/media/audio/audio_manager_base.cc
index ae429862ef9..5602fb28783 100644
--- a/chromium/media/audio/audio_manager_base.cc
+++ b/chromium/media/audio/audio_manager_base.cc
@@ -286,6 +286,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
// Turn off effects that weren't requested.
output_params.set_effects(params.effects() & output_params.effects());
}
+ output_params.set_latency_tag(params.latency_tag());
}
std::unique_ptr<DispatcherParams> dispatcher_params =
@@ -322,9 +323,6 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
return output_dispatchers_.back()->dispatcher->CreateStreamProxy();
}
-void AudioManagerBase::ShowAudioInputSettings() {
-}
-
void AudioManagerBase::GetAudioInputDeviceNames(
AudioDeviceNames* device_names) {
}
@@ -357,21 +355,6 @@ void AudioManagerBase::ShutdownOnAudioThread() {
// Close all output streams.
output_dispatchers_.clear();
-
-#if defined(OS_MACOSX)
- // On mac, AudioManager runs on the main thread, loop for which stops
- // processing task queue at this point. So even if tasks to close the
- // streams are enqueued, they would not run leading to CHECKs getting hit
- // in the destructor about open streams. Close them explicitly here.
- // crbug.com/608049.
- for (auto iter = input_streams_.begin(); iter != input_streams_.end();) {
- // Note: Closing the stream will invalidate the iterator.
- // Increment the iterator before closing the stream.
- AudioInputStream* stream = *iter++;
- stream->Close();
- }
- CHECK(input_streams_.empty());
-#endif // OS_MACOSX
}
void AudioManagerBase::AddOutputDeviceChangeListener(
diff --git a/chromium/media/audio/audio_manager_base.h b/chromium/media/audio/audio_manager_base.h
index 8e2fc15b1e9..b165d06f90b 100644
--- a/chromium/media/audio/audio_manager_base.h
+++ b/chromium/media/audio/audio_manager_base.h
@@ -107,7 +107,6 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
// AudioManager:
void ShutdownOnAudioThread() override;
base::string16 GetAudioInputDeviceModel() override;
- void ShowAudioInputSettings() override;
void GetAudioInputDeviceDescriptions(
AudioDeviceDescriptions* device_descriptions) final;
diff --git a/chromium/media/audio/audio_output_controller.cc b/chromium/media/audio/audio_output_controller.cc
index 90bd2cc2c52..dd03cc93aac 100644
--- a/chromium/media/audio/audio_output_controller.cc
+++ b/chromium/media/audio/audio_output_controller.cc
@@ -48,11 +48,12 @@ AudioOutputController::AudioOutputController(
params.sample_rate(),
TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMillis)),
on_more_io_data_called_(0),
- ignore_errors_during_stop_close_(false) {
+ weak_factory_for_errors_(this) {
DCHECK(audio_manager);
DCHECK(handler_);
DCHECK(sync_reader_);
DCHECK(message_loop_.get());
+ weak_this_for_errors_ = weak_factory_for_errors_.GetWeakPtr();
}
AudioOutputController::~AudioOutputController() {
@@ -284,7 +285,8 @@ int AudioOutputController::OnMoreData(base::TimeDelta delay,
sync_reader_->Read(dest);
- const int frames = dest->frames();
+ const int frames =
+ dest->is_bitstream_format() ? dest->GetBitstreamFrames() : dest->frames();
delay += AudioTimestampHelper::FramesToTime(frames, params_.sample_rate());
sync_reader_->RequestMoreData(delay, delay_timestamp, prior_frames_skipped);
@@ -341,15 +343,14 @@ void AudioOutputController::LogAudioPowerLevel(const std::string& call_name) {
}
void AudioOutputController::OnError() {
- {
- base::AutoLock auto_lock(error_lock_);
- if (ignore_errors_during_stop_close_)
- return;
- }
-
- // Handle error on the audio controller thread.
- message_loop_->PostTask(
- FROM_HERE, base::BindOnce(&AudioOutputController::DoReportError, this));
+ // Handle error on the audio controller thread. We defer errors for one
+ // second in case they are the result of a device change; delay chosen to
+ // exceed duration of device changes which take a few hundred milliseconds.
+ message_loop_->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&AudioOutputController::DoReportError,
+ weak_this_for_errors_),
+ base::TimeDelta::FromSeconds(1));
}
void AudioOutputController::DoStopCloseAndClearStream() {
@@ -357,10 +358,9 @@ void AudioOutputController::DoStopCloseAndClearStream() {
// Allow calling unconditionally and bail if we don't have a stream_ to close.
if (stream_) {
- {
- base::AutoLock auto_lock(error_lock_);
- ignore_errors_during_stop_close_ = true;
- }
+ // Ensure no errors will be delivered while we cycle streams and any that
+ // occurred immediately prior to the device change are dropped.
+ weak_factory_for_errors_.InvalidateWeakPtrs();
// De-register from state change callbacks if stream_ was created via
// AudioManager.
@@ -374,8 +374,8 @@ void AudioOutputController::DoStopCloseAndClearStream() {
diverting_to_stream_ = NULL;
stream_ = NULL;
- // Since the stream is no longer running, no lock is necessary.
- ignore_errors_during_stop_close_ = false;
+ // Since the stream is stopped, we can now update |weak_this_for_errors_|.
+ weak_this_for_errors_ = weak_factory_for_errors_.GetWeakPtr();
}
state_ = kEmpty;
diff --git a/chromium/media/audio/audio_output_controller.h b/chromium/media/audio/audio_output_controller.h
index 19fba1f9a68..537bf03250f 100644
--- a/chromium/media/audio/audio_output_controller.h
+++ b/chromium/media/audio/audio_output_controller.h
@@ -15,6 +15,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
@@ -65,7 +66,7 @@ class MEDIA_EXPORT AudioOutputController
: public base::RefCountedThreadSafe<AudioOutputController>,
public AudioOutputStream::AudioSourceCallback,
public AudioSourceDiverter,
- NON_EXPORTED_BASE(public AudioManager::AudioDeviceListener) {
+ public AudioManager::AudioDeviceListener {
public:
// An event handler that receives events from the AudioOutputController. The
// following methods are called on the audio manager thread.
@@ -266,15 +267,16 @@ class MEDIA_EXPORT AudioOutputController
base::AtomicRefCount on_more_io_data_called_;
std::unique_ptr<base::OneShotTimer> wedge_timer_;
- // Flag which indicates errors received during Stop/Close should be ignored.
- // These errors are generally harmless since a fresh stream is about to be
- // recreated, but if forwarded, renderer side clients may consider them
- // catastrophic and abort their operations.
+ // WeakPtrFactory and WeakPtr for ignoring errors which occur arround a
+ // Stop/Close cycle; e.g., device changes. These errors are generally harmless
+ // since a fresh stream is about to be recreated, but if forwarded, renderer
+ // side clients may consider them catastrophic and abort their operations.
//
- // If |stream_| is started then |ignore_errors_during_stop_close_| must only
- // be accessed while |error_lock_| is held.
- bool ignore_errors_during_stop_close_;
- base::Lock error_lock_;
+ // |weak_this_for_errors_| must not be reassigned while a stream is active or
+ // we'll have concurrent access from different threads. Only the factory may
+ // be used to invalidate WeakPtrs while the stream is active.
+ base::WeakPtr<AudioOutputController> weak_this_for_errors_;
+ base::WeakPtrFactory<AudioOutputController> weak_factory_for_errors_;
DISALLOW_COPY_AND_ASSIGN(AudioOutputController);
};
diff --git a/chromium/media/audio/audio_output_controller_unittest.cc b/chromium/media/audio/audio_output_controller_unittest.cc
index 2919808af64..a2f03f3161d 100644
--- a/chromium/media/audio/audio_output_controller_unittest.cc
+++ b/chromium/media/audio/audio_output_controller_unittest.cc
@@ -115,6 +115,7 @@ class AudioOutputControllerTest : public testing::Test {
AudioOutputControllerTest()
: audio_manager_(AudioManager::CreateForTesting(
base::MakeUnique<TestAudioThread>())) {
+ EXPECT_CALL(mock_event_handler_, OnLog(_)).Times(testing::AnyNumber());
base::RunLoop().RunUntilIdle();
}
@@ -212,7 +213,7 @@ class AudioOutputControllerTest : public testing::Test {
void ReadDuplicatedAudioData(const std::vector<MockAudioPushSink*>& sinks) {
for (size_t i = 0; i < sinks.size(); i++) {
- EXPECT_CALL(*sinks[i], OnDataCheck(kBufferNonZeroData));
+ EXPECT_CALL(*sinks[i], OnDataCheck(kBufferNonZeroData)).Times(AtLeast(1));
}
std::unique_ptr<AudioBus> dest = AudioBus::Create(params_);
@@ -256,6 +257,13 @@ class AudioOutputControllerTest : public testing::Test {
run_loop.Run();
}
+ void SimulateErrorThenDeviceChange() {
+ audio_manager_->GetTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AudioOutputControllerTest::TriggerErrorThenDeviceChange,
+ base::Unretained(this)));
+ }
+
// These help make test sequences more readable.
void DivertNeverPlaying() { Divert(false, 0); }
void DivertWillEventuallyBeTwicePlayed() { Divert(false, 2); }
@@ -264,6 +272,18 @@ class AudioOutputControllerTest : public testing::Test {
void RevertWhilePlaying() { Revert(true); }
private:
+ void TriggerErrorThenDeviceChange() {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+
+ // Errors should be deferred; the device change should ensure it's dropped.
+ EXPECT_CALL(mock_event_handler_, OnControllerError()).Times(0);
+ controller_->OnError();
+
+ EXPECT_CALL(mock_event_handler_, OnControllerPlaying());
+ EXPECT_CALL(mock_event_handler_, OnControllerPaused()).Times(0);
+ controller_->OnDeviceChange();
+ }
+
base::TestMessageLoop message_loop_;
std::unique_ptr<AudioManager> audio_manager_;
MockAudioOutputControllerEventHandler mock_event_handler_;
@@ -308,6 +328,13 @@ TEST_F(AudioOutputControllerTest, PlayDeviceChangeClose) {
Close();
}
+TEST_F(AudioOutputControllerTest, PlayDeviceChangeError) {
+ Create(kSamplesPerPacket);
+ Play();
+ SimulateErrorThenDeviceChange();
+ Close();
+}
+
TEST_F(AudioOutputControllerTest, PlayDivertRevertClose) {
Create(kSamplesPerPacket);
Play();
diff --git a/chromium/media/audio/audio_output_device.cc b/chromium/media/audio/audio_output_device.cc
index 1013ce6ad73..00cfe034dd1 100644
--- a/chromium/media/audio/audio_output_device.cc
+++ b/chromium/media/audio/audio_output_device.cc
@@ -14,7 +14,6 @@
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -179,7 +178,9 @@ bool AudioOutputDevice::CurrentThreadIsRenderingThread() {
void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
DCHECK(task_runner()->BelongsToCurrentThread());
DCHECK_EQ(state_, IDLE);
+
state_ = AUTHORIZING;
+ auth_start_time_ = base::TimeTicks::Now();
ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
security_origin_);
@@ -319,6 +320,12 @@ void AudioOutputDevice::OnDeviceAuthorized(
DCHECK(task_runner()->BelongsToCurrentThread());
auth_timeout_action_.reset();
+ // Times over 15 s should be very rare, so we don't lose interesting data by
+ // making it the upper limit.
+ UMA_HISTOGRAM_CUSTOM_TIMES("Media.Audio.Render.OutputDeviceAuthorizationTime",
+ base::TimeTicks::Now() - auth_start_time_,
+ base::TimeDelta::FromMilliseconds(1),
+ base::TimeDelta::FromSeconds(15), 100);
// Do nothing if late authorization is received after timeout.
if (state_ == IPC_CLOSED)
@@ -463,6 +470,7 @@ void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() {
AudioOutputBuffer* buffer =
reinterpret_cast<AudioOutputBuffer*>(shared_memory_.memory());
output_bus_ = AudioBus::WrapMemory(audio_parameters_, buffer->audio);
+ output_bus_->set_is_bitstream_format(audio_parameters_.IsBitstreamFormat());
}
// Called whenever we receive notifications about pending data.
@@ -500,6 +508,11 @@ void AudioOutputDevice::AudioThreadCallback::Process(uint32_t control_signal) {
// memory.
render_callback_->Render(delay, delay_timestamp, frames_skipped,
output_bus_.get());
+
+ if (audio_parameters_.IsBitstreamFormat()) {
+ buffer->params.bitstream_data_size = output_bus_->GetBitstreamDataSize();
+ buffer->params.bitstream_frames = output_bus_->GetBitstreamFrames();
+ }
}
bool AudioOutputDevice::AudioThreadCallback::
diff --git a/chromium/media/audio/audio_output_device.h b/chromium/media/audio/audio_output_device.h
index 9a883928666..88e18431b83 100644
--- a/chromium/media/audio/audio_output_device.h
+++ b/chromium/media/audio/audio_output_device.h
@@ -69,6 +69,7 @@
#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
#include "media/audio/audio_device_thread.h"
#include "media/audio/audio_output_ipc.h"
#include "media/audio/scoped_task_runner_observer.h"
@@ -83,10 +84,9 @@ class OneShotTimer;
namespace media {
-class MEDIA_EXPORT AudioOutputDevice
- : NON_EXPORTED_BASE(public AudioRendererSink),
- NON_EXPORTED_BASE(public AudioOutputIPCDelegate),
- NON_EXPORTED_BASE(public ScopedTaskRunnerObserver) {
+class MEDIA_EXPORT AudioOutputDevice : public AudioRendererSink,
+ public AudioOutputIPCDelegate,
+ public ScopedTaskRunnerObserver {
public:
// NOTE: Clients must call Initialize() before using.
AudioOutputDevice(
@@ -218,6 +218,9 @@ class MEDIA_EXPORT AudioOutputDevice
const base::TimeDelta auth_timeout_;
std::unique_ptr<base::OneShotTimer> auth_timeout_action_;
+ // Set when authorization starts, for UMA stats.
+ base::TimeTicks auth_start_time_;
+
DISALLOW_COPY_AND_ASSIGN(AudioOutputDevice);
};
diff --git a/chromium/media/audio/audio_output_device_unittest.cc b/chromium/media/audio/audio_output_device_unittest.cc
index bad1f8c72ae..9d05f6423fc 100644
--- a/chromium/media/audio/audio_output_device_unittest.cc
+++ b/chromium/media/audio/audio_output_device_unittest.cc
@@ -22,7 +22,7 @@
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/audio/audio_output_device.h"
-#include "media/audio/sample_rates.h"
+#include "media/base/sample_rates.h"
#include "media/base/test_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gmock_mutant.h"
@@ -48,6 +48,8 @@ const char kNonDefaultDeviceId[] = "valid-nondefault-device-id";
const char kUnauthorizedDeviceId[] = "unauthorized-device-id";
const int kAuthTimeoutForTestingMs = 500;
const int kOutputDelayMs = 20;
+const uint32_t kBitstreamFrames = 1024;
+const size_t kBitstreamDataSize = 512;
class MockRenderCallback : public AudioRendererSink::RenderCallback {
public:
@@ -62,6 +64,16 @@ class MockRenderCallback : public AudioRendererSink::RenderCallback {
MOCK_METHOD0(OnRenderError, void());
};
+void RenderAudioBus(base::TimeDelta delay,
+ base::TimeTicks timestamp,
+ int prior_frames_skipped,
+ AudioBus* dest) {
+ if (dest->is_bitstream_format()) {
+ dest->SetBitstreamFrames(kBitstreamFrames);
+ dest->SetBitstreamDataSize(kBitstreamDataSize);
+ }
+}
+
class MockAudioOutputIPC : public AudioOutputIPC {
public:
MockAudioOutputIPC() {}
@@ -109,15 +121,18 @@ class AudioOutputDeviceTest
AudioOutputDeviceTest();
~AudioOutputDeviceTest();
+ void SetupBitstreamParameters();
void ReceiveAuthorization(OutputDeviceStatus device_status);
void StartAudioDevice();
void CreateStream();
void ExpectRenderCallback();
void WaitUntilRenderCallback();
+ void WaitForAudioThreadCallbackProcessCompletion();
void StopAudioDevice();
void CreateDevice(const std::string& device_id);
void SetDevice(const std::string& device_id);
void CheckDeviceStatus(OutputDeviceStatus device_status);
+ void VerifyBitstreamFields();
protected:
// Used to clean up TLS pointers that the test(s) will initialize.
@@ -258,7 +273,7 @@ void AudioOutputDeviceTest::ExpectRenderCallback() {
EXPECT_CALL(
callback_,
Render(base::TimeDelta::FromMilliseconds(kOutputDelayMs), _, _, _))
- .WillOnce(DoAll(QuitLoop(io_loop_.task_runner()),
+ .WillOnce(DoAll(Invoke(RenderAudioBus), QuitLoop(io_loop_.task_runner()),
Return(kNumberOfFramesToProcess)));
}
@@ -270,6 +285,14 @@ void AudioOutputDeviceTest::WaitUntilRenderCallback() {
base::RunLoop().Run();
}
+void AudioOutputDeviceTest::WaitForAudioThreadCallbackProcessCompletion() {
+ uint32_t buffer_index;
+ size_t bytes_read = browser_socket_.ReceiveWithTimeout(
+ &buffer_index, sizeof(buffer_index),
+ base::TimeDelta::FromMilliseconds(900));
+ EXPECT_EQ(bytes_read, sizeof(buffer_index));
+}
+
void AudioOutputDeviceTest::StopAudioDevice() {
if (device_status_ == OUTPUT_DEVICE_STATUS_OK)
EXPECT_CALL(*audio_output_ipc_, CloseStream());
@@ -278,6 +301,19 @@ void AudioOutputDeviceTest::StopAudioDevice() {
base::RunLoop().RunUntilIdle();
}
+void AudioOutputDeviceTest::SetupBitstreamParameters() {
+ default_audio_parameters_.Reset(AudioParameters::AUDIO_BITSTREAM_EAC3,
+ CHANNEL_LAYOUT_STEREO, 48000, 16, 1024);
+ SetDevice(kNonDefaultDeviceId);
+}
+
+void AudioOutputDeviceTest::VerifyBitstreamFields() {
+ AudioOutputBuffer* buffer =
+ reinterpret_cast<AudioOutputBuffer*>(shared_memory_.memory());
+ EXPECT_EQ(kBitstreamDataSize, buffer->params.bitstream_data_size);
+ EXPECT_EQ(kBitstreamFrames, buffer->params.bitstream_frames);
+}
+
TEST_P(AudioOutputDeviceTest, Initialize) {
// Tests that the object can be constructed, initialized and destructed
// without having ever been started.
@@ -384,6 +420,17 @@ TEST_P(AudioOutputDeviceTest, AuthorizationTimedOut) {
base::RunLoop().RunUntilIdle();
}
+TEST_P(AudioOutputDeviceTest, BitstreamFormatTest) {
+ SetupBitstreamParameters();
+ StartAudioDevice();
+ ExpectRenderCallback();
+ CreateStream();
+ WaitUntilRenderCallback();
+ WaitForAudioThreadCallbackProcessCompletion();
+ VerifyBitstreamFields();
+ StopAudioDevice();
+}
+
INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
} // namespace media.
diff --git a/chromium/media/audio/audio_output_proxy_unittest.cc b/chromium/media/audio/audio_output_proxy_unittest.cc
index bb137ed90fa..5d932137dda 100644
--- a/chromium/media/audio/audio_output_proxy_unittest.cc
+++ b/chromium/media/audio/audio_output_proxy_unittest.cc
@@ -140,7 +140,6 @@ class MockAudioManager : public AudioManagerBase {
MOCK_METHOD0(HasAudioOutputDevices, bool());
MOCK_METHOD0(HasAudioInputDevices, bool());
MOCK_METHOD0(GetAudioInputDeviceModel, base::string16());
- MOCK_METHOD0(ShowAudioInputSettings, void());
MOCK_METHOD1(GetAudioInputDeviceNames,
void(media::AudioDeviceNames* device_name));
MOCK_METHOD2(GetPreferredOutputStreamParameters, AudioParameters(
diff --git a/chromium/media/audio/audio_output_resampler.cc b/chromium/media/audio/audio_output_resampler.cc
index 907955f91ee..9cac015748a 100644
--- a/chromium/media/audio/audio_output_resampler.cc
+++ b/chromium/media/audio/audio_output_resampler.cc
@@ -21,10 +21,10 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "media/audio/audio_output_proxy.h"
-#include "media/audio/sample_rates.h"
#include "media/base/audio_converter.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/limits.h"
+#include "media/base/sample_rates.h"
namespace media {
@@ -93,19 +93,15 @@ class OnMoreDataConverter
// Record UMA statistics for hardware output configuration.
static void RecordStats(const AudioParameters& output_params) {
- // Note the 'PRESUBMIT_IGNORE_UMA_MAX's below, these silence the PRESUBMIT.py
- // check for uma enum max usage, since we're abusing UMA_HISTOGRAM_ENUMERATION
- // to report a discrete value.
- UMA_HISTOGRAM_ENUMERATION(
- "Media.HardwareAudioBitsPerChannel",
- output_params.bits_per_sample(),
- limits::kMaxBitsPerSample); // PRESUBMIT_IGNORE_UMA_MAX
+ UMA_HISTOGRAM_EXACT_LINEAR("Media.HardwareAudioBitsPerChannel",
+ output_params.bits_per_sample(),
+ static_cast<int>(limits::kMaxBitsPerSample));
UMA_HISTOGRAM_ENUMERATION(
"Media.HardwareAudioChannelLayout", output_params.channel_layout(),
CHANNEL_LAYOUT_MAX + 1);
- UMA_HISTOGRAM_ENUMERATION(
- "Media.HardwareAudioChannelCount", output_params.channels(),
- limits::kMaxChannels); // PRESUBMIT_IGNORE_UMA_MAX
+ UMA_HISTOGRAM_EXACT_LINEAR("Media.HardwareAudioChannelCount",
+ output_params.channels(),
+ static_cast<int>(limits::kMaxChannels));
AudioSampleRate asr;
if (ToAudioSampleRate(output_params.sample_rate(), &asr)) {
@@ -121,19 +117,15 @@ static void RecordStats(const AudioParameters& output_params) {
// Record UMA statistics for hardware output configuration after fallback.
static void RecordFallbackStats(const AudioParameters& output_params) {
UMA_HISTOGRAM_BOOLEAN("Media.FallbackToHighLatencyAudioPath", true);
- // Note the 'PRESUBMIT_IGNORE_UMA_MAX's below, these silence the PRESUBMIT.py
- // check for uma enum max usage, since we're abusing UMA_HISTOGRAM_ENUMERATION
- // to report a discrete value.
- UMA_HISTOGRAM_ENUMERATION(
- "Media.FallbackHardwareAudioBitsPerChannel",
- output_params.bits_per_sample(),
- limits::kMaxBitsPerSample); // PRESUBMIT_IGNORE_UMA_MAX
+ UMA_HISTOGRAM_EXACT_LINEAR("Media.FallbackHardwareAudioBitsPerChannel",
+ output_params.bits_per_sample(),
+ static_cast<int>(limits::kMaxBitsPerSample));
UMA_HISTOGRAM_ENUMERATION(
"Media.FallbackHardwareAudioChannelLayout",
output_params.channel_layout(), CHANNEL_LAYOUT_MAX + 1);
- UMA_HISTOGRAM_ENUMERATION(
- "Media.FallbackHardwareAudioChannelCount", output_params.channels(),
- limits::kMaxChannels); // PRESUBMIT_IGNORE_UMA_MAX
+ UMA_HISTOGRAM_EXACT_LINEAR("Media.FallbackHardwareAudioChannelCount",
+ output_params.channels(),
+ static_cast<int>(limits::kMaxChannels));
AudioSampleRate asr;
if (ToAudioSampleRate(output_params.sample_rate(), &asr)) {
diff --git a/chromium/media/audio/audio_output_stream_sink.h b/chromium/media/audio/audio_output_stream_sink.h
index 19a5c464712..8407e9ee54a 100644
--- a/chromium/media/audio/audio_output_stream_sink.h
+++ b/chromium/media/audio/audio_output_stream_sink.h
@@ -27,7 +27,7 @@ namespace media {
// TODO(dalecurtis): Delete this class once we have a proper mojo audio service;
// tracked by http://crbug.com/425368
class MEDIA_EXPORT AudioOutputStreamSink
- : NON_EXPORTED_BASE(public RestartableAudioRendererSink),
+ : public RestartableAudioRendererSink,
public AudioOutputStream::AudioSourceCallback {
public:
AudioOutputStreamSink();
diff --git a/chromium/media/audio/audio_system.h b/chromium/media/audio/audio_system.h
index 8df7fa70a94..1338d887a0b 100644
--- a/chromium/media/audio/audio_system.h
+++ b/chromium/media/audio/audio_system.h
@@ -12,16 +12,10 @@
#include "media/base/audio_parameters.h"
#include "media/base/media_export.h"
-namespace base {
-class SingleThreadTaskRunner;
-}
-
namespace media {
class AudioManager;
-// Work in progress: Provides asynchronous interface to AudioManager. All the
-// AudioManager clients will be switched to it, in preparation for moving
-// to Mojo audio service.
+// Provides asynchronous interface to access audio device information
class MEDIA_EXPORT AudioSystem {
public:
// Replies are asynchronously sent from audio system thread to the thread the
@@ -36,8 +30,6 @@ class MEDIA_EXPORT AudioSystem {
using OnInputDeviceInfoCallback = base::OnceCallback<
void(const AudioParameters&, const AudioParameters&, const std::string&)>;
- // Must not be called on audio system thread if it differs from the one
- // AudioSystem is destroyed on. See http://crbug.com/705455.
static AudioSystem* Get();
virtual ~AudioSystem();
@@ -47,9 +39,8 @@ class MEDIA_EXPORT AudioSystem {
// of the device.
// TODO(olka,tommi): fix all AudioManager implementations to return invalid
// parameters if the device is not found.
- virtual void GetInputStreamParameters(
- const std::string& device_id,
- OnAudioParamsCallback on_params_cb) const = 0;
+ virtual void GetInputStreamParameters(const std::string& device_id,
+ OnAudioParamsCallback on_params_cb) = 0;
// If media::AudioDeviceDescription::IsDefaultDevice(device_id) is true,
// callback will receive the parameters of the default output device.
@@ -60,17 +51,17 @@ class MEDIA_EXPORT AudioSystem {
// parameters if the device is not found.
virtual void GetOutputStreamParameters(
const std::string& device_id,
- OnAudioParamsCallback on_params_cb) const = 0;
+ OnAudioParamsCallback on_params_cb) = 0;
- virtual void HasInputDevices(OnBoolCallback on_has_devices_cb) const = 0;
+ virtual void HasInputDevices(OnBoolCallback on_has_devices_cb) = 0;
- virtual void HasOutputDevices(OnBoolCallback on_has_devices_cb) const = 0;
+ virtual void HasOutputDevices(OnBoolCallback on_has_devices_cb) = 0;
// Replies with device descriptions of input audio devices if |for_input| is
// true, and of output audio devices otherwise.
virtual void GetDeviceDescriptions(
- OnDeviceDescriptionsCallback on_descriptions_cb,
- bool for_input) = 0;
+ bool for_input,
+ OnDeviceDescriptionsCallback on_descriptions_cb) = 0;
// Replies with an empty string if there is no associated output device found.
virtual void GetAssociatedOutputDeviceID(
@@ -84,8 +75,6 @@ class MEDIA_EXPORT AudioSystem {
const std::string& input_device_id,
OnInputDeviceInfoCallback on_input_device_info_cb) = 0;
- virtual base::SingleThreadTaskRunner* GetTaskRunner() const = 0;
-
protected:
// Sets the global AudioSystem pointer to the specified non-null value.
static void SetInstance(AudioSystem* audio_system);
diff --git a/chromium/media/audio/audio_system_impl.cc b/chromium/media/audio/audio_system_impl.cc
index 707ae2d9305..fb1e5b4341a 100644
--- a/chromium/media/audio/audio_system_impl.cc
+++ b/chromium/media/audio/audio_system_impl.cc
@@ -38,7 +38,7 @@ std::unique_ptr<AudioSystem> AudioSystemImpl::Create(
void AudioSystemImpl::GetInputStreamParameters(
const std::string& device_id,
- OnAudioParamsCallback on_params_cb) const {
+ OnAudioParamsCallback on_params_cb) {
if (GetTaskRunner()->BelongsToCurrentThread()) {
GetTaskRunner()->PostTask(FROM_HERE,
base::BindOnce(std::move(on_params_cb),
@@ -55,7 +55,7 @@ void AudioSystemImpl::GetInputStreamParameters(
void AudioSystemImpl::GetOutputStreamParameters(
const std::string& device_id,
- OnAudioParamsCallback on_params_cb) const {
+ OnAudioParamsCallback on_params_cb) {
if (GetTaskRunner()->BelongsToCurrentThread()) {
GetTaskRunner()->PostTask(FROM_HERE,
base::BindOnce(std::move(on_params_cb),
@@ -70,7 +70,7 @@ void AudioSystemImpl::GetOutputStreamParameters(
std::move(on_params_cb));
}
-void AudioSystemImpl::HasInputDevices(OnBoolCallback on_has_devices_cb) const {
+void AudioSystemImpl::HasInputDevices(OnBoolCallback on_has_devices_cb) {
if (GetTaskRunner()->BelongsToCurrentThread()) {
GetTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(std::move(on_has_devices_cb),
@@ -84,7 +84,7 @@ void AudioSystemImpl::HasInputDevices(OnBoolCallback on_has_devices_cb) const {
std::move(on_has_devices_cb));
}
-void AudioSystemImpl::HasOutputDevices(OnBoolCallback on_has_devices_cb) const {
+void AudioSystemImpl::HasOutputDevices(OnBoolCallback on_has_devices_cb) {
if (GetTaskRunner()->BelongsToCurrentThread()) {
GetTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(std::move(on_has_devices_cb),
@@ -99,8 +99,8 @@ void AudioSystemImpl::HasOutputDevices(OnBoolCallback on_has_devices_cb) const {
}
void AudioSystemImpl::GetDeviceDescriptions(
- OnDeviceDescriptionsCallback on_descriptions_cb,
- bool for_input) {
+ bool for_input,
+ OnDeviceDescriptionsCallback on_descriptions_cb) {
if (GetTaskRunner()->BelongsToCurrentThread()) {
GetTaskRunner()->PostTask(
FROM_HERE,
@@ -151,10 +151,6 @@ void AudioSystemImpl::GetInputDeviceInfo(
: media::BindToCurrentLoop(std::move(on_input_device_info_cb))));
}
-base::SingleThreadTaskRunner* AudioSystemImpl::GetTaskRunner() const {
- return audio_manager_->GetTaskRunner();
-}
-
// static
AudioParameters AudioSystemImpl::GetInputParametersOnDeviceThread(
AudioManager* audio_manager,
@@ -225,4 +221,8 @@ void AudioSystemImpl::GetInputDeviceInfoOnDeviceThread(
associated_output_device_id);
}
+base::SingleThreadTaskRunner* AudioSystemImpl::GetTaskRunner() const {
+ return audio_manager_->GetTaskRunner();
+}
+
} // namespace media
diff --git a/chromium/media/audio/audio_system_impl.h b/chromium/media/audio/audio_system_impl.h
index 4e799b87673..0850d8e54e6 100644
--- a/chromium/media/audio/audio_system_impl.h
+++ b/chromium/media/audio/audio_system_impl.h
@@ -21,20 +21,19 @@ class MEDIA_EXPORT AudioSystemImpl : public AudioSystem {
~AudioSystemImpl() override;
// AudioSystem implementation.
- void GetInputStreamParameters(
- const std::string& device_id,
- OnAudioParamsCallback on_params_cb) const override;
+ void GetInputStreamParameters(const std::string& device_id,
+ OnAudioParamsCallback on_params_cb) override;
- void GetOutputStreamParameters(
- const std::string& device_id,
- OnAudioParamsCallback on_params_cb) const override;
+ void GetOutputStreamParameters(const std::string& device_id,
+ OnAudioParamsCallback on_params_cb) override;
- void HasInputDevices(OnBoolCallback on_has_devices_cb) const override;
+ void HasInputDevices(OnBoolCallback on_has_devices_cb) override;
- void HasOutputDevices(OnBoolCallback on_has_devices_cb) const override;
+ void HasOutputDevices(OnBoolCallback on_has_devices_cb) override;
- void GetDeviceDescriptions(OnDeviceDescriptionsCallback on_descriptions_cp,
- bool for_input) override;
+ void GetDeviceDescriptions(
+ bool for_input,
+ OnDeviceDescriptionsCallback on_descriptions_cp) override;
void GetAssociatedOutputDeviceID(const std::string& input_device_id,
OnDeviceIdCallback on_device_id_cb) override;
@@ -43,14 +42,10 @@ class MEDIA_EXPORT AudioSystemImpl : public AudioSystem {
const std::string& input_device_id,
OnInputDeviceInfoCallback on_input_device_info_cb) override;
- base::SingleThreadTaskRunner* GetTaskRunner() const override;
-
protected:
AudioSystemImpl(AudioManager* audio_manager);
private:
- AudioManager* const audio_manager_;
-
static AudioParameters GetInputParametersOnDeviceThread(
AudioManager* audio_manager,
const std::string& device_id);
@@ -68,6 +63,10 @@ class MEDIA_EXPORT AudioSystemImpl : public AudioSystem {
const std::string& input_device_id,
AudioSystem::OnInputDeviceInfoCallback on_input_device_info_cb);
+ base::SingleThreadTaskRunner* GetTaskRunner() const;
+
+ AudioManager* const audio_manager_;
+
DISALLOW_COPY_AND_ASSIGN(AudioSystemImpl);
};
diff --git a/chromium/media/audio/audio_system_impl_unittest.cc b/chromium/media/audio/audio_system_impl_unittest.cc
index 7f0037935c2..8601050dc2c 100644
--- a/chromium/media/audio/audio_system_impl_unittest.cc
+++ b/chromium/media/audio/audio_system_impl_unittest.cc
@@ -241,9 +241,8 @@ TEST_P(AudioSystemImplTest, GetInputDeviceDescriptionsNoInputDevices) {
EXPECT_EQ(1, static_cast<int>(output_device_descriptions_.size()));
EXPECT_CALL(*this, DeviceDescriptionsReceived());
audio_system_->GetDeviceDescriptions(
- base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
- base::Unretained(this), input_device_descriptions_),
- true);
+ true, base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
+ base::Unretained(this), input_device_descriptions_));
WaitForCallback();
}
@@ -258,9 +257,8 @@ TEST_P(AudioSystemImplTest, GetInputDeviceDescriptions) {
EXPECT_EQ(1, static_cast<int>(output_device_descriptions_.size()));
EXPECT_CALL(*this, DeviceDescriptionsReceived());
audio_system_->GetDeviceDescriptions(
- base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
- base::Unretained(this), input_device_descriptions_),
- true);
+ true, base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
+ base::Unretained(this), input_device_descriptions_));
WaitForCallback();
}
@@ -271,9 +269,8 @@ TEST_P(AudioSystemImplTest, GetOutputDeviceDescriptionsNoInputDevices) {
EXPECT_EQ(1, static_cast<int>(input_device_descriptions_.size()));
EXPECT_CALL(*this, DeviceDescriptionsReceived());
audio_system_->GetDeviceDescriptions(
- base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
- base::Unretained(this), output_device_descriptions_),
- false);
+ false, base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
+ base::Unretained(this), output_device_descriptions_));
WaitForCallback();
}
@@ -288,9 +285,8 @@ TEST_P(AudioSystemImplTest, GetOutputDeviceDescriptions) {
EXPECT_EQ(1, static_cast<int>(input_device_descriptions_.size()));
EXPECT_CALL(*this, DeviceDescriptionsReceived());
audio_system_->GetDeviceDescriptions(
- base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
- base::Unretained(this), output_device_descriptions_),
- false);
+ false, base::Bind(&AudioSystemImplTest::OnGetDeviceDescriptions,
+ base::Unretained(this), output_device_descriptions_));
WaitForCallback();
}
diff --git a/chromium/media/audio/clockless_audio_sink.cc b/chromium/media/audio/clockless_audio_sink.cc
index bea6fe0943e..d95f40e05f9 100644
--- a/chromium/media/audio/clockless_audio_sink.cc
+++ b/chromium/media/audio/clockless_audio_sink.cc
@@ -84,7 +84,8 @@ ClocklessAudioSink::ClocklessAudioSink(const OutputDeviceInfo& device_info)
: device_info_(device_info),
initialized_(false),
playing_(false),
- hashing_(false) {}
+ hashing_(false),
+ is_optimized_for_hw_params_(true) {}
ClocklessAudioSink::~ClocklessAudioSink() {}
@@ -135,7 +136,7 @@ OutputDeviceInfo ClocklessAudioSink::GetOutputDeviceInfo() {
}
bool ClocklessAudioSink::IsOptimizedForHardwareParameters() {
- return false;
+ return is_optimized_for_hw_params_;
}
bool ClocklessAudioSink::CurrentThreadIsRenderingThread() {
@@ -152,4 +153,9 @@ std::string ClocklessAudioSink::GetAudioHashForTesting() {
return thread_ && hashing_ ? thread_->GetAudioHash() : std::string();
}
+void ClocklessAudioSink::SetIsOptimizedForHardwareParametersForTesting(
+ bool value) {
+ is_optimized_for_hw_params_ = value;
+}
+
} // namespace media
diff --git a/chromium/media/audio/clockless_audio_sink.h b/chromium/media/audio/clockless_audio_sink.h
index 029932c9ff9..fec3dd53165 100644
--- a/chromium/media/audio/clockless_audio_sink.h
+++ b/chromium/media/audio/clockless_audio_sink.h
@@ -17,8 +17,7 @@ class ClocklessAudioSinkThread;
// Implementation of an AudioRendererSink that consumes the audio as fast as
// possible. This class does not support multiple Play()/Pause() events.
-class MEDIA_EXPORT ClocklessAudioSink
- : NON_EXPORTED_BASE(public AudioRendererSink) {
+class MEDIA_EXPORT ClocklessAudioSink : public AudioRendererSink {
public:
ClocklessAudioSink();
explicit ClocklessAudioSink(const OutputDeviceInfo& device_info);
@@ -44,6 +43,8 @@ class MEDIA_EXPORT ClocklessAudioSink
// Returns the hash of all audio frames seen since construction.
std::string GetAudioHashForTesting();
+ void SetIsOptimizedForHardwareParametersForTesting(bool value);
+
protected:
~ClocklessAudioSink() override;
@@ -53,6 +54,7 @@ class MEDIA_EXPORT ClocklessAudioSink
bool initialized_;
bool playing_;
bool hashing_;
+ bool is_optimized_for_hw_params_;
// Time taken in last set of Render() calls.
base::TimeDelta playback_time_;
diff --git a/chromium/media/audio/cras/audio_manager_cras.cc b/chromium/media/audio/cras/audio_manager_cras.cc
index 1029ebe8e49..3221531661f 100644
--- a/chromium/media/audio/cras/audio_manager_cras.cc
+++ b/chromium/media/audio/cras/audio_manager_cras.cc
@@ -13,12 +13,12 @@
#include "base/command_line.h"
#include "base/environment.h"
#include "base/logging.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram_macros.h"
#include "base/nix/xdg_util.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
#include "base/sys_info.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/audio/audio_device.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "media/audio/audio_device_description.h"
@@ -46,13 +46,12 @@ const int kDefaultSampleRate = 48000;
// Default input buffer size.
const int kDefaultInputBufferSize = 1024;
-const char kBeamformingOnDeviceId[] = "default-beamforming-on";
-const char kBeamformingOffDeviceId[] = "default-beamforming-off";
-
const char kInternalInputVirtualDevice[] = "Built-in mic";
const char kInternalOutputVirtualDevice[] = "Built-in speaker";
const char kHeadphoneLineOutVirtualDevice[] = "Headphone/Line Out";
+// Used for the Media.CrosBeamformingDeviceState histogram, currently not used
+// since beamforming is disabled.
enum CrosBeamformingDeviceState {
BEAMFORMING_DEFAULT_ENABLED = 0,
BEAMFORMING_USER_ENABLED,
@@ -61,30 +60,24 @@ enum CrosBeamformingDeviceState {
BEAMFORMING_STATE_MAX = BEAMFORMING_USER_DISABLED
};
-void RecordBeamformingDeviceState(CrosBeamformingDeviceState state) {
- UMA_HISTOGRAM_ENUMERATION("Media.CrosBeamformingDeviceState", state,
- BEAMFORMING_STATE_MAX + 1);
-}
-
-bool IsBeamformingDefaultEnabled() {
- return base::FieldTrialList::FindFullName("ChromebookBeamforming") ==
- "Enabled";
+bool HasKeyboardMic(const chromeos::AudioDeviceList& devices) {
+ for (const auto& device : devices) {
+ if (device.is_input && device.type == chromeos::AUDIO_TYPE_KEYBOARD_MIC) {
+ return true;
+ }
+ }
+ return false;
}
-// Returns a mic positions string if the machine has a beamforming capable
-// internal mic and otherwise an empty string.
-std::string MicPositions() {
- // Get the list of devices from CRAS. An internal mic with a non-empty
- // positions field indicates the machine has a beamforming capable mic array.
- chromeos::AudioDeviceList devices;
- chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
+const chromeos::AudioDevice* GetDeviceFromId(
+ const chromeos::AudioDeviceList& devices,
+ uint64_t id) {
for (const auto& device : devices) {
- if (device.type == chromeos::AUDIO_TYPE_INTERNAL_MIC) {
- // There should be only one internal mic device.
- return device.mic_positions;
+ if (device.id == id) {
+ return &device;
}
}
- return "";
+ return nullptr;
}
// Process |device_list| that two shares the same dev_index by creating a
@@ -110,44 +103,13 @@ void ProcessVirtualDeviceName(AudioDeviceNames* device_names,
} // namespace
-// Adds the beamforming on and off devices to |device_names|.
-void AudioManagerCras::AddBeamformingDevices(AudioDeviceNames* device_names) {
- DCHECK(device_names->empty());
- const std::string beamforming_on_name =
- GetLocalizedStringUTF8(BEAMFORMING_ON_DEFAULT_AUDIO_INPUT_DEVICE_NAME);
- const std::string beamforming_off_name =
- GetLocalizedStringUTF8(BEAMFORMING_OFF_DEFAULT_AUDIO_INPUT_DEVICE_NAME);
-
- if (IsBeamformingDefaultEnabled()) {
- // The first device in the list is expected to have a "default" device ID.
- // Web apps may depend on this behavior.
- beamforming_on_device_id_ = AudioDeviceDescription::kDefaultDeviceId;
- beamforming_off_device_id_ = kBeamformingOffDeviceId;
-
- // Users in the experiment will have the "beamforming on" device appear
- // first in the list. This causes it to be selected by default.
- device_names->push_back(
- AudioDeviceName(beamforming_on_name, beamforming_on_device_id_));
- device_names->push_back(
- AudioDeviceName(beamforming_off_name, beamforming_off_device_id_));
- } else {
- beamforming_off_device_id_ = AudioDeviceDescription::kDefaultDeviceId;
- beamforming_on_device_id_ = kBeamformingOnDeviceId;
-
- device_names->push_back(
- AudioDeviceName(beamforming_off_name, beamforming_off_device_id_));
- device_names->push_back(
- AudioDeviceName(beamforming_on_name, beamforming_on_device_id_));
- }
-}
-
bool AudioManagerCras::HasAudioOutputDevices() {
return true;
}
bool AudioManagerCras::HasAudioInputDevices() {
chromeos::AudioDeviceList devices;
- chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
+ GetAudioDevices(&devices);
for (size_t i = 0; i < devices.size(); ++i) {
if (devices[i].is_input && devices[i].is_for_simple_usage())
return true;
@@ -158,31 +120,25 @@ bool AudioManagerCras::HasAudioInputDevices() {
AudioManagerCras::AudioManagerCras(std::unique_ptr<AudioThread> audio_thread,
AudioLogFactory* audio_log_factory)
: AudioManagerBase(std::move(audio_thread), audio_log_factory),
- beamforming_on_device_id_(nullptr),
- beamforming_off_device_id_(nullptr) {
+ on_shutdown_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED),
+ main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ weak_ptr_factory_(this) {
+ weak_this_ = weak_ptr_factory_.GetWeakPtr();
SetMaxOutputStreamsAllowed(kMaxOutputStreams);
}
AudioManagerCras::~AudioManagerCras() = default;
-void AudioManagerCras::ShowAudioInputSettings() {
- NOTIMPLEMENTED();
-}
-
void AudioManagerCras::GetAudioDeviceNamesImpl(bool is_input,
AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
- // At least two mic positions indicates we have a beamforming capable mic
- // array. Add the virtual beamforming device to the list. When this device is
- // queried through GetInputStreamParameters, provide the cached mic positions.
- if (is_input && mic_positions_.size() > 1)
- AddBeamformingDevices(device_names);
- else
- device_names->push_back(AudioDeviceName::CreateDefault());
+
+ device_names->push_back(AudioDeviceName::CreateDefault());
if (base::FeatureList::IsEnabled(features::kEnumerateAudioDevices)) {
chromeos::AudioDeviceList devices;
- chromeos::CrasAudioHandler::Get()->GetAudioDevices(&devices);
+ GetAudioDevices(&devices);
// |dev_idx_map| is a map of dev_index and their audio devices.
std::map<int, chromeos::AudioDeviceList> dev_idx_map;
@@ -209,7 +165,6 @@ void AudioManagerCras::GetAudioDeviceNamesImpl(bool is_input,
void AudioManagerCras::GetAudioInputDeviceNames(
AudioDeviceNames* device_names) {
- mic_positions_ = ParsePointsFromString(MicPositions());
GetAudioDeviceNamesImpl(true, device_names);
}
@@ -231,34 +186,11 @@ AudioParameters AudioManagerCras::GetInputStreamParameters(
AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_STEREO, kDefaultSampleRate, 16,
buffer_size);
- if (chromeos::CrasAudioHandler::Get()->HasKeyboardMic())
+ chromeos::AudioDeviceList devices;
+ GetAudioDevices(&devices);
+ if (HasKeyboardMic(devices))
params.set_effects(AudioParameters::KEYBOARD_MIC);
- if (mic_positions_.size() > 1) {
- // We have the mic_positions_ check here because one of the beamforming
- // devices will have been assigned the "default" ID, which could otherwise
- // be confused with the ID in the non-beamforming-capable-device case.
- DCHECK(beamforming_on_device_id_);
- DCHECK(beamforming_off_device_id_);
-
- if (device_id == beamforming_on_device_id_) {
- params.set_mic_positions(mic_positions_);
-
- // Record a UMA metric based on the state of the experiment and the
- // selected device. This will tell us i) how common it is for users to
- // manually adjust the beamforming device and ii) how contaminated our
- // metric experiment buckets are.
- if (IsBeamformingDefaultEnabled())
- RecordBeamformingDeviceState(BEAMFORMING_DEFAULT_ENABLED);
- else
- RecordBeamformingDeviceState(BEAMFORMING_USER_ENABLED);
- } else if (device_id == beamforming_off_device_id_) {
- if (!IsBeamformingDefaultEnabled())
- RecordBeamformingDeviceState(BEAMFORMING_DEFAULT_DISABLED);
- else
- RecordBeamformingDeviceState(BEAMFORMING_USER_DISABLED);
- }
- }
return params;
}
@@ -268,27 +200,22 @@ std::string AudioManagerCras::GetAssociatedOutputDeviceID(
return "";
chromeos::AudioDeviceList devices;
- chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get();
- audio_handler->GetAudioDevices(&devices);
-
- if ((beamforming_on_device_id_ &&
- input_device_id == beamforming_on_device_id_) ||
- (beamforming_off_device_id_ &&
- input_device_id == beamforming_off_device_id_)) {
- // These are special devices derived from the internal mic array, so they
- // should be associated to the internal speaker.
- const chromeos::AudioDevice* internal_speaker =
- audio_handler->GetDeviceByType(chromeos::AUDIO_TYPE_INTERNAL_SPEAKER);
- return internal_speaker ? base::Uint64ToString(internal_speaker->id) : "";
- }
+ GetAudioDevices(&devices);
- // At this point, we know we have an ordinary input device, so we look up its
- // device_name, which identifies which hardware device it belongs to.
uint64_t device_id = 0;
- if (!base::StringToUint64(input_device_id, &device_id))
- return "";
+ if (input_device_id == AudioDeviceDescription::kDefaultDeviceId) {
+ return AudioDeviceDescription::kDefaultDeviceId;
+ } else {
+ // At this point, we know we have an ordinary input device id, so we parse
+ // the string for its device_id.
+ if (!base::StringToUint64(input_device_id, &device_id))
+ return "";
+ }
+
+ // Find the device in the device list to get the device name (identifying the
+ // hardware device).
const chromeos::AudioDevice* input_device =
- audio_handler->GetDeviceFromId(device_id);
+ GetDeviceFromId(devices, device_id);
if (!input_device)
return "";
@@ -306,14 +233,36 @@ std::string AudioManagerCras::GetAssociatedOutputDeviceID(
}
std::string AudioManagerCras::GetDefaultOutputDeviceID() {
- return base::Uint64ToString(
- chromeos::CrasAudioHandler::Get()->GetPrimaryActiveOutputNode());
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ uint64_t active_output_node_id = 0;
+ if (main_task_runner_->BelongsToCurrentThread()) {
+ // Unittest may use the same thread for audio thread.
+ GetPrimaryActiveOutputNodeOnMainThread(&active_output_node_id, &event);
+ } else {
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &AudioManagerCras::GetPrimaryActiveOutputNodeOnMainThread,
+ weak_this_, base::Unretained(&active_output_node_id),
+ base::Unretained(&event)));
+ }
+ WaitEventOrShutdown(&event);
+ return base::Uint64ToString(active_output_node_id);
}
const char* AudioManagerCras::GetName() {
return "CRAS";
}
+bool AudioManagerCras::Shutdown() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ on_shutdown_.Signal();
+ return AudioManager::Shutdown();
+}
+
AudioOutputStream* AudioManagerCras::MakeLinearOutputStream(
const AudioParameters& params,
const LogCallback& log_callback) {
@@ -347,15 +296,24 @@ AudioInputStream* AudioManagerCras::MakeLowLatencyInputStream(
return MakeInputStream(params, device_id);
}
-int AudioManagerCras::GetMinimumOutputBufferSizePerBoard() {
- // On faster boards we can use smaller buffer size for lower latency.
- // On slower boards we should use larger buffer size to prevent underrun.
- std::string board = base::SysInfo::GetLsbReleaseBoard();
- if (board == "kevin")
- return 768;
- else if (board == "samus")
- return 256;
- return 512;
+int AudioManagerCras::GetDefaultOutputBufferSizePerBoard() {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ int32_t buffer_size = 512;
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ if (main_task_runner_->BelongsToCurrentThread()) {
+ // Unittest may use the same thread for audio thread.
+ GetDefaultOutputBufferSizeOnMainThread(&buffer_size, &event);
+ } else {
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &AudioManagerCras::GetDefaultOutputBufferSizeOnMainThread,
+ weak_this_, base::Unretained(&buffer_size),
+ base::Unretained(&event)));
+ }
+ WaitEventOrShutdown(&event);
+ return static_cast<int>(buffer_size);
}
AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters(
@@ -363,7 +321,7 @@ AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters(
const AudioParameters& input_params) {
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = kDefaultSampleRate;
- int buffer_size = GetMinimumOutputBufferSizePerBoard();
+ int buffer_size = GetDefaultOutputBufferSizePerBoard();
int bits_per_sample = 16;
if (input_params.IsValid()) {
sample_rate = input_params.sample_rate();
@@ -417,4 +375,85 @@ bool AudioManagerCras::IsDefault(const std::string& device_id, bool is_input) {
return device_name.unique_id == device_id;
}
+void AudioManagerCras::GetAudioDevices(chromeos::AudioDeviceList* devices) {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ if (main_task_runner_->BelongsToCurrentThread()) {
+ GetAudioDevicesOnMainThread(devices, &event);
+ } else {
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AudioManagerCras::GetAudioDevicesOnMainThread,
+ weak_this_, base::Unretained(devices),
+ base::Unretained(&event)));
+ }
+ WaitEventOrShutdown(&event);
+}
+
+void AudioManagerCras::GetAudioDevicesOnMainThread(
+ chromeos::AudioDeviceList* devices,
+ base::WaitableEvent* event) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ // CrasAudioHandler is shut down before AudioManagerCras.
+ if (chromeos::CrasAudioHandler::IsInitialized()) {
+ chromeos::CrasAudioHandler::Get()->GetAudioDevices(devices);
+ }
+ event->Signal();
+}
+
+uint64_t AudioManagerCras::GetPrimaryActiveInputNode() {
+ DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ uint64_t device_id = 0;
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ if (main_task_runner_->BelongsToCurrentThread()) {
+ GetPrimaryActiveInputNodeOnMainThread(&device_id, &event);
+ } else {
+ main_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AudioManagerCras::GetPrimaryActiveInputNodeOnMainThread,
+ weak_this_, &device_id, &event));
+ }
+ WaitEventOrShutdown(&event);
+ return device_id;
+}
+
+void AudioManagerCras::GetPrimaryActiveInputNodeOnMainThread(
+ uint64_t* active_input_node_id,
+ base::WaitableEvent* event) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (chromeos::CrasAudioHandler::IsInitialized()) {
+ *active_input_node_id =
+ chromeos::CrasAudioHandler::Get()->GetPrimaryActiveInputNode();
+ }
+ event->Signal();
+}
+
+void AudioManagerCras::GetPrimaryActiveOutputNodeOnMainThread(
+ uint64_t* active_output_node_id,
+ base::WaitableEvent* event) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (chromeos::CrasAudioHandler::IsInitialized()) {
+ *active_output_node_id =
+ chromeos::CrasAudioHandler::Get()->GetPrimaryActiveOutputNode();
+ }
+ event->Signal();
+}
+
+void AudioManagerCras::GetDefaultOutputBufferSizeOnMainThread(
+ int32_t* buffer_size,
+ base::WaitableEvent* event) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (chromeos::CrasAudioHandler::IsInitialized()) {
+ chromeos::CrasAudioHandler::Get()->GetDefaultOutputBufferSize(buffer_size);
+ }
+ event->Signal();
+}
+
+void AudioManagerCras::WaitEventOrShutdown(base::WaitableEvent* event) {
+ base::WaitableEvent* waitables[] = {event, &on_shutdown_};
+ base::WaitableEvent::WaitMany(waitables, arraysize(waitables));
+}
+
} // namespace media
diff --git a/chromium/media/audio/cras/audio_manager_cras.h b/chromium/media/audio/cras/audio_manager_cras.h
index 7cf1200dde1..bf8a3dbf2db 100644
--- a/chromium/media/audio/cras/audio_manager_cras.h
+++ b/chromium/media/audio/cras/audio_manager_cras.h
@@ -14,6 +14,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "chromeos/audio/audio_device.h"
#include "media/audio/audio_manager_base.h"
namespace media {
@@ -27,7 +28,6 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
// AudioManager implementation.
bool HasAudioOutputDevices() override;
bool HasAudioInputDevices() override;
- void ShowAudioInputSettings() override;
void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
AudioParameters GetInputStreamParameters(
@@ -36,6 +36,7 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
const std::string& input_device_id) override;
std::string GetDefaultOutputDeviceID() override;
const char* GetName() override;
+ bool Shutdown() override;
// AudioManagerBase implementation.
AudioOutputStream* MakeLinearOutputStream(
@@ -74,18 +75,35 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
AudioInputStream* MakeInputStream(const AudioParameters& params,
const std::string& device_id);
- // Get minimum output buffer size for this board.
- int GetMinimumOutputBufferSizePerBoard();
+ // Get default output buffer size for this board.
+ int GetDefaultOutputBufferSizePerBoard();
void GetAudioDeviceNamesImpl(bool is_input, AudioDeviceNames* device_names);
- void AddBeamformingDevices(AudioDeviceNames* device_names);
+ void GetAudioDevices(chromeos::AudioDeviceList* devices);
+ void GetAudioDevicesOnMainThread(chromeos::AudioDeviceList* devices,
+ base::WaitableEvent* event);
+ uint64_t GetPrimaryActiveInputNode();
+ void GetPrimaryActiveInputNodeOnMainThread(uint64_t* active_input_node_id,
+ base::WaitableEvent* event);
+ void GetPrimaryActiveOutputNodeOnMainThread(uint64_t* active_output_node_id,
+ base::WaitableEvent* event);
+ void GetDefaultOutputBufferSizeOnMainThread(int32_t* buffer_size,
+ base::WaitableEvent* event);
- // Stores the mic positions field from the device.
- std::vector<Point> mic_positions_;
+ void WaitEventOrShutdown(base::WaitableEvent* event);
- const char* beamforming_on_device_id_;
- const char* beamforming_off_device_id_;
+ // Signaled if AudioManagerCras is shutting down.
+ base::WaitableEvent on_shutdown_;
+
+ // Task runner of browser main thread. CrasAudioHandler should be only
+ // accessed on this thread.
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+
+ // For posting tasks from audio thread to |main_task_runner_|.
+ base::WeakPtr<AudioManagerCras> weak_this_;
+
+ base::WeakPtrFactory<AudioManagerCras> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AudioManagerCras);
};
diff --git a/chromium/media/audio/cras/cras_input.cc b/chromium/media/audio/cras/cras_input.cc
index b5ac5012ff3..5243a5714b2 100644
--- a/chromium/media/audio/cras/cras_input.cc
+++ b/chromium/media/audio/cras/cras_input.cc
@@ -288,29 +288,23 @@ void CrasInputStream::ReadAudio(size_t frames,
const timespec* sample_ts) {
DCHECK(callback_);
- timespec latency_ts = {0, 0};
-
- // Determine latency and pass that on to the sink. sample_ts is the wall time
- // indicating when the first sample in the buffer was captured. Convert that
- // to latency in bytes.
- cras_client_calc_capture_latency(sample_ts, &latency_ts);
- double latency_usec =
- latency_ts.tv_sec * base::Time::kMicrosecondsPerSecond +
- latency_ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond;
- double frames_latency =
- latency_usec * params_.sample_rate() / base::Time::kMicrosecondsPerSecond;
- unsigned int bytes_latency =
- static_cast<unsigned int>(frames_latency * bytes_per_frame_);
-
// Update the AGC volume level once every second. Note that, |volume| is
// also updated each time SetVolume() is called through IPC by the
// render-side AGC.
double normalized_volume = 0.0;
GetAgcVolume(&normalized_volume);
- audio_bus_->FromInterleaved(
- buffer, audio_bus_->frames(), params_.bits_per_sample() / 8);
- callback_->OnData(this, audio_bus_.get(), bytes_latency, normalized_volume);
+ // Warning: It is generally unsafe to manufacture TimeTicks values; but
+ // here it is required for interfacing with cras. Assumption: cras
+ // is providing the timestamp from the CLOCK_MONOTONIC POSIX clock.
+ const base::TimeTicks capture_time =
+ base::TimeTicks() + base::TimeDelta::FromTimeSpec(*sample_ts);
+ DCHECK_EQ(base::TimeTicks::GetClock(),
+ base::TimeTicks::Clock::LINUX_CLOCK_MONOTONIC);
+
+ audio_bus_->FromInterleaved(buffer, audio_bus_->frames(),
+ params_.bits_per_sample() / 8);
+ callback_->OnData(this, audio_bus_.get(), capture_time, normalized_volume);
}
void CrasInputStream::NotifyStreamError(int err) {
diff --git a/chromium/media/audio/cras/cras_input_unittest.cc b/chromium/media/audio/cras/cras_input_unittest.cc
index 46bad85b881..4015b7f0908 100644
--- a/chromium/media/audio/cras/cras_input_unittest.cc
+++ b/chromium/media/audio/cras/cras_input_unittest.cc
@@ -14,6 +14,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "chromeos/audio/cras_audio_handler.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/cras/audio_manager_cras.h"
#include "media/audio/fake_audio_log_factory.h"
@@ -37,8 +38,9 @@ namespace media {
class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
public:
- MOCK_METHOD4(OnData,
- void(AudioInputStream*, const AudioBus*, uint32_t, double));
+ MOCK_METHOD4(
+ OnData,
+ void(AudioInputStream*, const AudioBus*, base::TimeTicks, double));
MOCK_METHOD1(OnError, void(AudioInputStream*));
};
@@ -64,11 +66,15 @@ class MockAudioManagerCrasInput : public AudioManagerCras {
class CrasInputStreamTest : public testing::Test {
protected:
CrasInputStreamTest() {
+ chromeos::CrasAudioHandler::InitializeForTesting();
mock_manager_.reset(new StrictMock<MockAudioManagerCrasInput>());
base::RunLoop().RunUntilIdle();
}
- ~CrasInputStreamTest() override { mock_manager_->Shutdown(); }
+ ~CrasInputStreamTest() override {
+ chromeos::CrasAudioHandler::Shutdown();
+ mock_manager_->Shutdown();
+ }
CrasInputStream* CreateStream(ChannelLayout layout) {
return CreateStream(layout, kTestFramesPerPacket);
diff --git a/chromium/media/audio/cras/cras_unified_unittest.cc b/chromium/media/audio/cras/cras_unified_unittest.cc
index 3bb52fc7244..7da8fc04513 100644
--- a/chromium/media/audio/cras/cras_unified_unittest.cc
+++ b/chromium/media/audio/cras/cras_unified_unittest.cc
@@ -14,6 +14,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
+#include "chromeos/audio/cras_audio_handler.h"
#include "media/audio/audio_device_description.h"
#include "media/audio/cras/audio_manager_cras.h"
#include "media/audio/fake_audio_log_factory.h"
@@ -59,11 +60,15 @@ class MockAudioManagerCras : public AudioManagerCras {
class CrasUnifiedStreamTest : public testing::Test {
protected:
CrasUnifiedStreamTest() {
+ chromeos::CrasAudioHandler::InitializeForTesting();
mock_manager_.reset(new StrictMock<MockAudioManagerCras>());
base::RunLoop().RunUntilIdle();
}
- ~CrasUnifiedStreamTest() override { mock_manager_->Shutdown(); }
+ ~CrasUnifiedStreamTest() override {
+ chromeos::CrasAudioHandler::Shutdown();
+ mock_manager_->Shutdown();
+ }
CrasUnifiedStream* CreateStream(ChannelLayout layout) {
return CreateStream(layout, kTestFramesPerPacket);
diff --git a/chromium/media/audio/fake_audio_input_stream.cc b/chromium/media/audio/fake_audio_input_stream.cc
index 188d05c7fb1..acf2561c8fc 100644
--- a/chromium/media/audio/fake_audio_input_stream.cc
+++ b/chromium/media/audio/fake_audio_input_stream.cc
@@ -106,7 +106,7 @@ void FakeAudioInputStream::ReadAudioFromSource() {
audio_source_->OnMoreData(base::TimeDelta(), base::TimeTicks::Now(), 0,
audio_bus_.get());
- callback_->OnData(this, audio_bus_.get(), 0, 1.0);
+ callback_->OnData(this, audio_bus_.get(), base::TimeTicks::Now(), 1.0);
}
using AudioSourceCallback = AudioOutputStream::AudioSourceCallback;
diff --git a/chromium/media/audio/fake_audio_input_stream.h b/chromium/media/audio/fake_audio_input_stream.h
index bafa7a1c70d..0be1b7f6fbf 100644
--- a/chromium/media/audio/fake_audio_input_stream.h
+++ b/chromium/media/audio/fake_audio_input_stream.h
@@ -13,8 +13,8 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "media/audio/audio_io.h"
-#include "media/audio/fake_audio_worker.h"
#include "media/base/audio_parameters.h"
+#include "media/base/fake_audio_worker.h"
namespace media {
diff --git a/chromium/media/audio/fake_audio_log_factory.h b/chromium/media/audio/fake_audio_log_factory.h
index d78d533361e..2a6d62a9d60 100644
--- a/chromium/media/audio/fake_audio_log_factory.h
+++ b/chromium/media/audio/fake_audio_log_factory.h
@@ -13,8 +13,7 @@
namespace media {
// Creates stub AudioLog instances, for testing, which do nothing.
-class MEDIA_EXPORT FakeAudioLogFactory
- : NON_EXPORTED_BASE(public AudioLogFactory) {
+class MEDIA_EXPORT FakeAudioLogFactory : public AudioLogFactory {
public:
FakeAudioLogFactory();
~FakeAudioLogFactory() override;
diff --git a/chromium/media/audio/fake_audio_output_stream.h b/chromium/media/audio/fake_audio_output_stream.h
index d4a9adec956..fea278be25a 100644
--- a/chromium/media/audio/fake_audio_output_stream.h
+++ b/chromium/media/audio/fake_audio_output_stream.h
@@ -9,8 +9,8 @@
#include "base/macros.h"
#include "media/audio/audio_io.h"
-#include "media/audio/fake_audio_worker.h"
#include "media/base/audio_parameters.h"
+#include "media/base/fake_audio_worker.h"
namespace media {
diff --git a/chromium/media/audio/fake_audio_worker.cc b/chromium/media/audio/fake_audio_worker.cc
deleted file mode 100644
index a68b6ef7504..00000000000
--- a/chromium/media/audio/fake_audio_worker.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/fake_audio_worker.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/cancelable_callback.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/synchronization/lock.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "media/base/audio_parameters.h"
-
-namespace media {
-
-class FakeAudioWorker::Worker
- : public base::RefCountedThreadSafe<FakeAudioWorker::Worker> {
- public:
- Worker(const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
- const AudioParameters& params);
-
- bool IsStopped();
- void Start(const base::Closure& worker_cb);
- void Stop();
-
- private:
- friend class base::RefCountedThreadSafe<Worker>;
- ~Worker();
-
- // Initialize and start regular calls to DoRead() on the worker thread.
- void DoStart();
-
- // Cancel any delayed callbacks to DoRead() in the worker loop's queue.
- void DoCancel();
-
- // Task that regularly calls |worker_cb_| according to the playback rate as
- // determined by the audio parameters given during construction. Runs on
- // the worker loop.
- void DoRead();
-
- const scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
- const base::TimeDelta buffer_duration_;
-
- base::Lock worker_cb_lock_; // Held while mutating or running |worker_cb_|.
- base::Closure worker_cb_;
- base::TimeTicks next_read_time_;
-
- // Used to cancel any delayed tasks still inside the worker loop's queue.
- base::CancelableClosure worker_task_cb_;
-
- base::ThreadChecker thread_checker_;
-
- DISALLOW_COPY_AND_ASSIGN(Worker);
-};
-
-FakeAudioWorker::FakeAudioWorker(
- const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
- const AudioParameters& params)
- : worker_(new Worker(worker_task_runner, params)) {
-}
-
-FakeAudioWorker::~FakeAudioWorker() {
- DCHECK(worker_->IsStopped());
-}
-
-void FakeAudioWorker::Start(const base::Closure& worker_cb) {
- DCHECK(worker_->IsStopped());
- worker_->Start(worker_cb);
-}
-
-void FakeAudioWorker::Stop() {
- worker_->Stop();
-}
-
-FakeAudioWorker::Worker::Worker(
- const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
- const AudioParameters& params)
- : worker_task_runner_(worker_task_runner),
- buffer_duration_(base::TimeDelta::FromMicroseconds(
- params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
- static_cast<float>(params.sample_rate()))) {
- // Worker can be constructed on any thread, but will DCHECK that its
- // Start/Stop methods are called from the same thread.
- thread_checker_.DetachFromThread();
-}
-
-FakeAudioWorker::Worker::~Worker() {
- DCHECK(worker_cb_.is_null());
-}
-
-bool FakeAudioWorker::Worker::IsStopped() {
- base::AutoLock scoped_lock(worker_cb_lock_);
- return worker_cb_.is_null();
-}
-
-void FakeAudioWorker::Worker::Start(const base::Closure& worker_cb) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!worker_cb.is_null());
- {
- base::AutoLock scoped_lock(worker_cb_lock_);
- DCHECK(worker_cb_.is_null());
- worker_cb_ = worker_cb;
- }
- worker_task_runner_->PostTask(FROM_HERE, base::Bind(&Worker::DoStart, this));
-}
-
-void FakeAudioWorker::Worker::DoStart() {
- DCHECK(worker_task_runner_->BelongsToCurrentThread());
- next_read_time_ = base::TimeTicks::Now();
- worker_task_cb_.Reset(base::Bind(&Worker::DoRead, this));
- worker_task_cb_.callback().Run();
-}
-
-void FakeAudioWorker::Worker::Stop() {
- DCHECK(thread_checker_.CalledOnValidThread());
- {
- base::AutoLock scoped_lock(worker_cb_lock_);
- if (worker_cb_.is_null())
- return;
- worker_cb_.Reset();
- }
- worker_task_runner_->PostTask(FROM_HERE, base::Bind(&Worker::DoCancel, this));
-}
-
-void FakeAudioWorker::Worker::DoCancel() {
- DCHECK(worker_task_runner_->BelongsToCurrentThread());
- worker_task_cb_.Cancel();
-}
-
-void FakeAudioWorker::Worker::DoRead() {
- DCHECK(worker_task_runner_->BelongsToCurrentThread());
-
- {
- base::AutoLock scoped_lock(worker_cb_lock_);
- if (!worker_cb_.is_null())
- worker_cb_.Run();
- }
-
- // Need to account for time spent here due to the cost of |worker_cb| as well
- // as the imprecision of PostDelayedTask().
- const base::TimeTicks now = base::TimeTicks::Now();
- base::TimeDelta delay = next_read_time_ + buffer_duration_ - now;
-
- // If we're behind, find the next nearest ontime interval.
- if (delay < base::TimeDelta())
- delay += buffer_duration_ * (-delay / buffer_duration_ + 1);
- next_read_time_ = now + delay;
-
- worker_task_runner_->PostDelayedTask(
- FROM_HERE, worker_task_cb_.callback(), delay);
-}
-
-} // namespace media
diff --git a/chromium/media/audio/fake_audio_worker.h b/chromium/media/audio/fake_audio_worker.h
deleted file mode 100644
index 4b0241bebc3..00000000000
--- a/chromium/media/audio/fake_audio_worker.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_FAKE_AUDIO_WORKER_H_
-#define MEDIA_AUDIO_FAKE_AUDIO_WORKER_H_
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "media/base/media_export.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace media {
-class AudioParameters;
-
-// A fake audio worker. Using a provided message loop, FakeAudioWorker will
-// call back the provided callback like a real audio consumer or producer would.
-class MEDIA_EXPORT FakeAudioWorker {
- public:
- // |worker_task_runner| is the task runner on which the closure provided to
- // Start() will be executed on. This may or may not be the be for the same
- // thread that invokes the Start/Stop methods.
- // |params| is used to determine the frequency of callbacks.
- FakeAudioWorker(
- const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner,
- const AudioParameters& params);
- ~FakeAudioWorker();
-
- // Start executing |worker_cb| at a regular intervals. Stop() must be called
- // by the same thread before destroying FakeAudioWorker.
- void Start(const base::Closure& worker_cb);
-
- // Stop executing the closure provided to Start(). Blocks until the worker
- // loop is not inside a closure invocation. Safe to call multiple times.
- // Must be called on the same thread that called Start().
- void Stop();
-
- private:
- // All state and implementation is kept within this ref-counted class because
- // cancellation of posted tasks must happen on the worker thread some time
- // after the call to Stop() (on the main thread) returns.
- class Worker;
- const scoped_refptr<Worker> worker_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeAudioWorker);
-};
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_FAKE_AUDIO_WORKER_H_
diff --git a/chromium/media/audio/fake_audio_worker_unittest.cc b/chromium/media/audio/fake_audio_worker_unittest.cc
deleted file mode 100644
index e78ddb7d75a..00000000000
--- a/chromium/media/audio/fake_audio_worker_unittest.cc
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/time.h"
-#include "media/audio/fake_audio_worker.h"
-#include "media/audio/simple_sources.h"
-#include "media/base/audio_parameters.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-
-static const int kTestCallbacks = 5;
-
-class FakeAudioWorkerTest : public testing::Test {
- public:
- FakeAudioWorkerTest()
- : params_(
- AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 8, 128),
- fake_worker_(message_loop_.task_runner(), params_),
- seen_callbacks_(0) {
- time_between_callbacks_ = base::TimeDelta::FromMicroseconds(
- params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
- static_cast<float>(params_.sample_rate()));
- }
-
- ~FakeAudioWorkerTest() override {}
-
- void CalledByFakeWorker() {
- seen_callbacks_++;
- }
-
- void RunOnAudioThread() {
- ASSERT_TRUE(message_loop_.task_runner()->BelongsToCurrentThread());
- fake_worker_.Start(base::Bind(
- &FakeAudioWorkerTest::CalledByFakeWorker, base::Unretained(this)));
- }
-
- void RunOnceOnAudioThread() {
- ASSERT_TRUE(message_loop_.task_runner()->BelongsToCurrentThread());
- RunOnAudioThread();
- // Start() should immediately post a task to run the callback, so we
- // should end up with only a single callback being run.
- message_loop_.task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&FakeAudioWorkerTest::EndTest, base::Unretained(this), 1));
- }
-
- void StopStartOnAudioThread() {
- ASSERT_TRUE(message_loop_.task_runner()->BelongsToCurrentThread());
- fake_worker_.Stop();
- RunOnAudioThread();
- }
-
- void TimeCallbacksOnAudioThread(int callbacks) {
- ASSERT_TRUE(message_loop_.task_runner()->BelongsToCurrentThread());
-
- if (seen_callbacks_ == 0) {
- RunOnAudioThread();
- start_time_ = base::TimeTicks::Now();
- }
-
- // Keep going until we've seen the requested number of callbacks.
- if (seen_callbacks_ < callbacks) {
- message_loop_.task_runner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
- base::Unretained(this), callbacks),
- time_between_callbacks_ / 2);
- } else {
- end_time_ = base::TimeTicks::Now();
- EndTest(callbacks);
- }
- }
-
- void EndTest(int callbacks) {
- ASSERT_TRUE(message_loop_.task_runner()->BelongsToCurrentThread());
- fake_worker_.Stop();
- EXPECT_LE(callbacks, seen_callbacks_);
- message_loop_.task_runner()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
- }
-
- protected:
- base::MessageLoop message_loop_;
- AudioParameters params_;
- FakeAudioWorker fake_worker_;
- base::TimeTicks start_time_;
- base::TimeTicks end_time_;
- base::TimeDelta time_between_callbacks_;
- int seen_callbacks_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FakeAudioWorkerTest);
-};
-
-// Ensure the worker runs on the audio thread and fires callbacks.
-TEST_F(FakeAudioWorkerTest, FakeBasicCallback) {
- message_loop_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&FakeAudioWorkerTest::RunOnceOnAudioThread,
- base::Unretained(this)));
- base::RunLoop().Run();
-}
-
-// Ensure the time between callbacks is sane.
-TEST_F(FakeAudioWorkerTest, TimeBetweenCallbacks) {
- message_loop_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
- base::Unretained(this), kTestCallbacks));
- base::RunLoop().Run();
-
- // There are only (kTestCallbacks - 1) intervals between kTestCallbacks.
- base::TimeDelta actual_time_between_callbacks =
- (end_time_ - start_time_) / (seen_callbacks_ - 1);
-
- // Ensure callback time is no faster than the expected time between callbacks.
- EXPECT_GE(actual_time_between_callbacks, time_between_callbacks_);
-
- // Softly check if the callback time is no slower than twice the expected time
- // between callbacks. Since this test runs on the bots we can't be too strict
- // with the bounds.
- if (actual_time_between_callbacks > 2 * time_between_callbacks_)
- LOG(ERROR) << "Time between fake audio callbacks is too large!";
-}
-
-// Ensure Start()/Stop() on the worker doesn't generate too many callbacks. See
-// http://crbug.com/159049.
-TEST_F(FakeAudioWorkerTest, StartStopClearsCallbacks) {
- message_loop_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&FakeAudioWorkerTest::TimeCallbacksOnAudioThread,
- base::Unretained(this), kTestCallbacks));
-
- // Issue a Stop() / Start() in between expected callbacks to maximize the
- // chance of catching the worker doing the wrong thing.
- message_loop_.task_runner()->PostDelayedTask(
- FROM_HERE, base::Bind(&FakeAudioWorkerTest::StopStartOnAudioThread,
- base::Unretained(this)),
- time_between_callbacks_ / 2);
-
- // EndTest() will ensure the proper number of callbacks have occurred.
- base::RunLoop().Run();
-}
-
-} // namespace media
diff --git a/chromium/media/audio/fuchsia/audio_manager_fuchsia.cc b/chromium/media/audio/fuchsia/audio_manager_fuchsia.cc
index 661e6816d5f..7bc5d23315c 100644
--- a/chromium/media/audio/fuchsia/audio_manager_fuchsia.cc
+++ b/chromium/media/audio/fuchsia/audio_manager_fuchsia.cc
@@ -26,10 +26,6 @@ bool AudioManagerFuchsia::HasAudioInputDevices() {
return false;
}
-void AudioManagerFuchsia::ShowAudioInputSettings() {
- NOTIMPLEMENTED();
-}
-
void AudioManagerFuchsia::GetAudioInputDeviceNames(
AudioDeviceNames* device_names) {
device_names->clear();
diff --git a/chromium/media/audio/fuchsia/audio_manager_fuchsia.h b/chromium/media/audio/fuchsia/audio_manager_fuchsia.h
index 9ab3a17860a..7ce59254984 100644
--- a/chromium/media/audio/fuchsia/audio_manager_fuchsia.h
+++ b/chromium/media/audio/fuchsia/audio_manager_fuchsia.h
@@ -18,7 +18,6 @@ class AudioManagerFuchsia : public AudioManagerBase {
// Implementation of AudioManager.
bool HasAudioOutputDevices() override;
bool HasAudioInputDevices() override;
- void ShowAudioInputSettings() override;
void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
AudioParameters GetInputStreamParameters(
diff --git a/chromium/media/audio/mac/audio_input_mac.cc b/chromium/media/audio/mac/audio_input_mac.cc
index aebe146ea7e..106b03e8240 100644
--- a/chromium/media/audio/mac/audio_input_mac.cc
+++ b/chromium/media/audio/mac/audio_input_mac.cc
@@ -252,6 +252,8 @@ void PCMQueueInAudioInputStream::HandleInputBuffer(
// TODO(dalecurtis): This is a HACK. Long term the AudioQueue path is going
// away in favor of the AudioUnit based AUAudioInputStream(). Tracked by
// http://crbug.com/161383.
+ // TODO(dalecurtis): Delete all this. It shouldn't be necessary now that we
+ // have a ring buffer and FIFO on the actual shared memory.
base::TimeDelta elapsed = base::TimeTicks::Now() - last_fill_;
const base::TimeDelta kMinDelay = base::TimeDelta::FromMilliseconds(5);
if (elapsed < kMinDelay) {
@@ -260,11 +262,19 @@ void PCMQueueInAudioInputStream::HandleInputBuffer(
base::PlatformThread::Sleep(kMinDelay - elapsed);
}
+ // TODO(dalecurtis): This should be updated to include the device latency,
+ // but really since Pepper (which ignores the delay value) is on the only
+ // one creating AUDIO_PCM_LINEAR input devices, it doesn't matter.
+ // https://lists.apple.com/archives/coreaudio-api/2017/Jul/msg00035.html
+ const base::TimeTicks capture_time =
+ start_time->mFlags & kAudioTimeStampHostTimeValid
+ ? base::TimeTicks::FromMachAbsoluteTime(start_time->mHostTime)
+ : base::TimeTicks::Now();
+
uint8_t* audio_data = reinterpret_cast<uint8_t*>(audio_buffer->mAudioData);
- audio_bus_->FromInterleaved(
- audio_data, audio_bus_->frames(), format_.mBitsPerChannel / 8);
- callback_->OnData(
- this, audio_bus_.get(), audio_buffer->mAudioDataByteSize, 0.0);
+ audio_bus_->FromInterleaved(audio_data, audio_bus_->frames(),
+ format_.mBitsPerChannel / 8);
+ callback_->OnData(this, audio_bus_.get(), capture_time, 0.0);
last_fill_ = base::TimeTicks::Now();
}
diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac.cc b/chromium/media/audio/mac/audio_low_latency_input_mac.cc
index f0dc947ce77..c112138bd06 100644
--- a/chromium/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/chromium/media/audio/mac/audio_low_latency_input_mac.cc
@@ -18,6 +18,7 @@
#include "base/trace_event/trace_event.h"
#include "media/audio/mac/audio_manager_mac.h"
#include "media/base/audio_bus.h"
+#include "media/base/audio_timestamp_helper.h"
#include "media/base/data_buffer.h"
namespace media {
@@ -229,7 +230,6 @@ AUAudioInputStream::AUAudioInputStream(
sink_(nullptr),
audio_unit_(0),
input_device_id_(audio_device_id),
- hardware_latency_frames_(0),
number_of_channels_in_frame_(0),
fifo_(input_params.channels(),
number_of_frames_,
@@ -485,7 +485,7 @@ bool AUAudioInputStream::Open() {
}
// The hardware latency is fixed and will not change during the call.
- hardware_latency_frames_ = GetHardwareLatency();
+ hardware_latency_ = GetHardwareLatency();
// The master channel is 0, Left and right are channels 1 and 2.
// And the master channel is not counted in |number_of_channels_in_frame_|.
@@ -901,8 +901,7 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
if (number_of_frames != number_of_frames_ && number_of_frames_provided_ == 0)
number_of_frames_provided_ = number_of_frames;
- // Update the capture latency.
- double capture_latency_frames = GetCaptureLatency(time_stamp);
+ base::TimeTicks capture_time = GetCaptureTime(time_stamp);
// The AGC volume level is updated once every second on a separate thread.
// Note that, |volume| is also updated each time SetVolume() is called
@@ -912,8 +911,6 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
AudioBuffer& buffer = io_data->mBuffers[0];
uint8_t* audio_data = reinterpret_cast<uint8_t*>(buffer.mData);
- uint32_t capture_delay_bytes = static_cast<uint32_t>(
- (capture_latency_frames + 0.5) * format_.mBytesPerFrame);
DCHECK(audio_data);
if (!audio_data)
return kAudioUnitErr_InvalidElement;
@@ -936,6 +933,10 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
fifo_.IncreaseCapacity(blocks);
}
+ // Compensate the capture time for the FIFO before pushing an new frames.
+ capture_time -= AudioTimestampHelper::FramesToTime(fifo_.GetAvailableFrames(),
+ format_.mSampleRate);
+
// Copy captured (and interleaved) data into FIFO.
fifo_.Push(audio_data, number_of_frames, format_.mBitsPerChannel / 8);
@@ -944,9 +945,11 @@ OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames,
const AudioBus* audio_bus = fifo_.Consume();
DCHECK_EQ(audio_bus->frames(), static_cast<int>(number_of_frames_));
- // Compensate the audio delay caused by the FIFO.
- capture_delay_bytes += fifo_.GetAvailableFrames() * format_.mBytesPerFrame;
- sink_->OnData(this, audio_bus, capture_delay_bytes, normalized_volume);
+ sink_->OnData(this, audio_bus, capture_time, normalized_volume);
+
+ // Move the capture time forward for each vended block.
+ capture_time += AudioTimestampHelper::FramesToTime(audio_bus->frames(),
+ format_.mSampleRate);
}
return noErr;
@@ -1056,10 +1059,10 @@ int AUAudioInputStream::HardwareSampleRate() {
return static_cast<int>(nominal_sample_rate);
}
-double AUAudioInputStream::GetHardwareLatency() {
+base::TimeDelta AUAudioInputStream::GetHardwareLatency() {
if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
- return 0.0;
+ return base::TimeDelta();
}
// Get audio unit latency.
@@ -1081,23 +1084,21 @@ double AUAudioInputStream::GetHardwareLatency() {
nullptr, &size, &device_latency_frames);
DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
- return static_cast<double>((audio_unit_latency_sec * format_.mSampleRate) +
- device_latency_frames);
+ return base::TimeDelta::FromSecondsD(audio_unit_latency_sec) +
+ AudioTimestampHelper::FramesToTime(device_latency_frames,
+ format_.mSampleRate);
}
-double AUAudioInputStream::GetCaptureLatency(
+base::TimeTicks AUAudioInputStream::GetCaptureTime(
const AudioTimeStamp* input_time_stamp) {
- // Get the delay between between the actual recording instant and the time
- // when the data packet is provided as a callback.
- UInt64 capture_time_ns =
- AudioConvertHostTimeToNanos(input_time_stamp->mHostTime);
- UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
- double delay_frames = static_cast<double>(1e-9 * (now_ns - capture_time_ns) *
- format_.mSampleRate);
-
// Total latency is composed by the dynamic latency and the fixed
// hardware latency.
- return (delay_frames + hardware_latency_frames_);
+ // https://lists.apple.com/archives/coreaudio-api/2017/Jul/msg00035.html
+ return (input_time_stamp->mFlags & kAudioTimeStampHostTimeValid
+ ? base::TimeTicks::FromMachAbsoluteTime(
+ input_time_stamp->mHostTime)
+ : base::TimeTicks::Now()) -
+ hardware_latency_;
}
int AUAudioInputStream::GetNumberOfChannelsFromStream() {
diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac.h b/chromium/media/audio/mac/audio_low_latency_input_mac.h
index df2f7a73154..7d03db5b4a2 100644
--- a/chromium/media/audio/mac/audio_low_latency_input_mac.h
+++ b/chromium/media/audio/mac/audio_low_latency_input_mac.h
@@ -138,10 +138,10 @@ class MEDIA_EXPORT AUAudioInputStream
// Gets the fixed capture hardware latency and store it during initialization.
// Returns 0 if not available.
- double GetHardwareLatency();
+ base::TimeDelta GetHardwareLatency();
- // Gets the current capture delay value.
- double GetCaptureLatency(const AudioTimeStamp* input_time_stamp);
+ // Gets the current capture time.
+ base::TimeTicks GetCaptureTime(const AudioTimeStamp* input_time_stamp);
// Gets the number of channels for a stream of audio data.
int GetNumberOfChannelsFromStream();
@@ -220,8 +220,8 @@ class MEDIA_EXPORT AUAudioInputStream
// array as soon as a frame of the desired buffer size has been recorded.
std::unique_ptr<uint8_t[]> audio_data_buffer_;
- // Fixed capture hardware latency in frames.
- double hardware_latency_frames_;
+ // Fixed capture hardware latency.
+ base::TimeDelta hardware_latency_;
// The number of channels in each frame of audio data, which is used
// when querying the volume of each channel.
diff --git a/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc b/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc
index 6002e2030e0..e54af7c3f1e 100644
--- a/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc
+++ b/chromium/media/audio/mac/audio_low_latency_input_mac_unittest.cc
@@ -43,7 +43,7 @@ class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
MOCK_METHOD4(OnData,
void(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume));
MOCK_METHOD1(OnError, void(AudioInputStream* stream));
};
@@ -86,7 +86,7 @@ class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
// AudioInputStream::AudioInputCallback implementation.
void OnData(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
const int num_samples = src->frames() * src->channels();
std::unique_ptr<int16_t> interleaved(new int16_t[num_samples]);
@@ -217,8 +217,8 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyMonoRecording) {
base::RunLoop run_loop;
EXPECT_CALL(sink, OnData(ais, NotNull(), _, _))
.Times(AtLeast(10))
- .WillRepeatedly(CheckCountAndPostQuitTask(
- &count, 10, &message_loop_, run_loop.QuitClosure()));
+ .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &message_loop_,
+ run_loop.QuitClosure()));
ais->Start(&sink);
run_loop.Run();
ais->Stop();
@@ -252,8 +252,8 @@ TEST_F(MacAudioInputTest, AUAudioInputStreamVerifyStereoRecording) {
base::RunLoop run_loop;
EXPECT_CALL(sink, OnData(ais, NotNull(), _, _))
.Times(AtLeast(10))
- .WillRepeatedly(CheckCountAndPostQuitTask(
- &count, 10, &message_loop_, run_loop.QuitClosure()));
+ .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10, &message_loop_,
+ run_loop.QuitClosure()));
ais->Start(&sink);
run_loop.Run();
ais->Stop();
diff --git a/chromium/media/audio/mac/audio_manager_mac.cc b/chromium/media/audio/mac/audio_manager_mac.cc
index 8478e0f70c5..7e406a2ee2f 100644
--- a/chromium/media/audio/mac/audio_manager_mac.cc
+++ b/chromium/media/audio/mac/audio_manager_mac.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/mac/mac_logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/macros.h"
@@ -22,6 +23,7 @@
#include "media/audio/mac/audio_auhal_mac.h"
#include "media/audio/mac/audio_input_mac.h"
#include "media/audio/mac/audio_low_latency_input_mac.h"
+#include "media/audio/mac/coreaudio_dispatch_override.h"
#include "media/audio/mac/scoped_audio_unit.h"
#include "media/base/audio_parameters.h"
#include "media/base/bind_to_current_loop.h"
@@ -529,6 +531,27 @@ void AudioManagerMac::ShutdownOnAudioThread() {
// and IncreaseIOBufferSizeIfPossible() which both touches native Core Audio
// APIs and they can fail and disrupt tests during shutdown.
in_shutdown_ = true;
+
+ // Even if tasks to close the streams are enqueued, they would not run
+ // leading to CHECKs getting hit in the destructor about open streams. Close
+ // them explicitly here. crbug.com/608049.
+ for (auto iter = basic_input_streams_.begin();
+ iter != basic_input_streams_.end();) {
+ // Note: Closing the stream will invalidate the iterator.
+ // Increment the iterator before closing the stream.
+ AudioInputStream* stream = *iter++;
+ stream->Close();
+ }
+ for (auto iter = low_latency_input_streams_.begin();
+ iter != low_latency_input_streams_.end();) {
+ // Note: Closing the stream will invalidate the iterator.
+ // Increment the iterator before closing the stream.
+ AudioInputStream* stream = *iter++;
+ stream->Close();
+ }
+ CHECK(basic_input_streams_.empty());
+ CHECK(low_latency_input_streams_.empty());
+
AudioManagerBase::ShutdownOnAudioThread();
}
@@ -870,6 +893,8 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
void AudioManagerMac::InitializeOnAudioThread() {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+ if (base::FeatureList::IsEnabled(kSerializeCoreAudioPauseResume))
+ InitializeCoreAudioDispatchOverride();
power_observer_.reset(new AudioPowerObserver());
}
diff --git a/chromium/media/audio/mac/audio_manager_mac.h b/chromium/media/audio/mac/audio_manager_mac.h
index 0dbaec35cb5..80ceeb19150 100644
--- a/chromium/media/audio/mac/audio_manager_mac.h
+++ b/chromium/media/audio/mac/audio_manager_mac.h
@@ -84,7 +84,7 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
// Streams should consult ShouldDeferStreamStart() and if true check the value
// again after |kStartDelayInSecsForPowerEvents| has elapsed. If false, the
// stream may be started immediately.
- // TOOD(henrika): track UMA statistics related to defer start to come up with
+ // TODO(henrika): track UMA statistics related to defer start to come up with
// a suitable delay value.
enum { kStartDelayInSecsForPowerEvents = 5 };
bool ShouldDeferStreamStart() const;
diff --git a/chromium/media/audio/mac/coreaudio_dispatch_override.cc b/chromium/media/audio/mac/coreaudio_dispatch_override.cc
new file mode 100644
index 00000000000..0bd1fc5f3f9
--- /dev/null
+++ b/chromium/media/audio/mac/coreaudio_dispatch_override.cc
@@ -0,0 +1,147 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/audio/mac/coreaudio_dispatch_override.h"
+
+#include <dispatch/dispatch.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+
+namespace {
+struct dyld_interpose_tuple {
+ template <typename T>
+ dyld_interpose_tuple(const T* replacement, const T* replacee)
+ : replacement(reinterpret_cast<const void*>(replacement)),
+ replacee(reinterpret_cast<const void*>(replacee)) {}
+ const void* replacement;
+ const void* replacee;
+};
+} // namespace
+
+// This method, and the tuple above, is defined in dyld_priv.h; see:
+// https://github.com/opensource-apple/dyld/blob/master/include/mach-o/dyld_priv.h
+extern "C" void dyld_dynamic_interpose(
+ const struct mach_header* mh,
+ const struct dyld_interpose_tuple array[],
+ size_t count) __attribute__((weak_import));
+
+namespace media {
+namespace {
+const char kCoreAudioPath[] =
+ "/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio";
+
+dispatch_queue_t g_pause_resume_queue = nullptr;
+bool g_dispatch_override_installed = false;
+base::subtle::AtomicWord g_resumeio_callsite = 0;
+base::subtle::AtomicWord g_pauseio_callsite = 0;
+
+bool AddressIsPauseOrResume(intptr_t address) {
+ if (address == 0)
+ return false;
+
+ intptr_t resumeio_callsite =
+ base::subtle::NoBarrier_Load(&g_resumeio_callsite);
+
+ if (address == resumeio_callsite)
+ return true;
+
+ intptr_t pauseio_callsite = base::subtle::NoBarrier_Load(&g_pauseio_callsite);
+ if (address == pauseio_callsite)
+ return true;
+
+ if (resumeio_callsite && pauseio_callsite)
+ return false;
+
+ // We don't know both callsites yet, so try to look up the caller.
+ Dl_info info;
+ if (!dladdr(reinterpret_cast<const void*>(address), &info))
+ return false;
+
+ DCHECK_EQ(strcmp(info.dli_fname, kCoreAudioPath), 0);
+
+ if (!resumeio_callsite && info.dli_sname &&
+ strcmp(info.dli_sname, "HALC_IOContext_ResumeIO") == 0) {
+ resumeio_callsite = address;
+ base::subtle::NoBarrier_CompareAndSwap(&g_resumeio_callsite, 0,
+ resumeio_callsite);
+ }
+ if (!pauseio_callsite && info.dli_sname &&
+ strcmp(info.dli_sname, "HALC_IOContext_PauseIO") == 0) {
+ pauseio_callsite = address;
+ base::subtle::NoBarrier_CompareAndSwap(&g_pauseio_callsite, 0,
+ pauseio_callsite);
+ }
+
+ return address == pauseio_callsite || address == resumeio_callsite;
+}
+
+dispatch_queue_t GetGlobalQueueOverride(long identifier, unsigned long flags) {
+ // Get the return address.
+ const intptr_t* rbp = 0;
+ asm("movq %%rbp, %0;" : "=r"(rbp));
+ const intptr_t caller = rbp[1];
+
+ // Check if it's one we should override.
+ if (identifier == DISPATCH_QUEUE_PRIORITY_HIGH &&
+ AddressIsPauseOrResume(caller)) {
+ return g_pause_resume_queue;
+ }
+
+ return dispatch_get_global_queue(identifier, flags);
+}
+
+} // namespace
+
+bool InitializeCoreAudioDispatchOverride() {
+ if (g_dispatch_override_installed)
+ return true;
+
+ DCHECK_EQ(g_pause_resume_queue, nullptr);
+
+ if (!base::mac::IsAtLeastOS10_10()) {
+ return false;
+ }
+
+ // This function should be available in macOS > 10.10.
+ if (dyld_dynamic_interpose == nullptr) {
+ LOG(ERROR) << "Unable to resolve dyld_dynamic_interpose()";
+ return false;
+ }
+ // Get CoreAudio handle
+ void* coreaudio = dlopen(kCoreAudioPath, RTLD_LAZY);
+ if (!coreaudio) {
+ LOG(ERROR) << "Could not load CoreAudio while trying to initialize "
+ "dispatch override";
+ return false;
+ }
+ // Retrieve the base address (also address of Mach header). For this
+ // we need any external symbol to look up.
+ const void* symbol = dlsym(coreaudio, "AudioObjectGetPropertyData");
+ if (!symbol) {
+ LOG(ERROR) << "Unable to resolve AudioObjectGetPropertyData in "
+ "CoreAudio library";
+ return false;
+ }
+ // From the address of that symbol, we can get the address of the library's
+ // header.
+ Dl_info info = {};
+ if (!dladdr(symbol, &info)) {
+ LOG(ERROR) << "Unable to find Mach header for CoreAudio library.";
+ return false;
+ }
+ const auto* header = reinterpret_cast<const mach_header*>(info.dli_fbase);
+ g_pause_resume_queue =
+ dispatch_queue_create("org.chromium.CoreAudioPauseResumeQueue", nullptr);
+ dyld_interpose_tuple interposition(&GetGlobalQueueOverride,
+ &dispatch_get_global_queue);
+ dyld_dynamic_interpose(header, &interposition, 1);
+ g_dispatch_override_installed = true;
+ return true;
+}
+
+} // namespace media
diff --git a/chromium/media/audio/mac/coreaudio_dispatch_override.h b/chromium/media/audio/mac/coreaudio_dispatch_override.h
new file mode 100644
index 00000000000..efd9f8c12b2
--- /dev/null
+++ b/chromium/media/audio/mac/coreaudio_dispatch_override.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_AUDIO_MAC_COREAUDIO_DISPATCH_OVERRIDE_H_
+#define MEDIA_AUDIO_MAC_COREAUDIO_DISPATCH_OVERRIDE_H_
+
+namespace media {
+// Initializes a CoreAudio hotfix, if supported (macOS >= 10.10).
+// See: http://crbug.com/772410
+// The hotfix overrides calls to dispatch_get_global_queue() from two CoreAudio
+// functions: HALC_IOContext_PauseIO and HALC_IOContext_ResumeIO. These dispatch
+// blocks that should execute in-order, but the global queue does not guarantee
+// this. When the calls execute out-of-order, we stop receiving callbacks for
+// audio streams on one or more devices.
+//
+// To circumvent this problem, these two functions get handed an internal serial
+// queue instead. For all other callers, the override will just defer to the
+// normal dispatch_get_global_queue() implementation.
+//
+// Calls to this function must be serialized. Will do nothing if called when
+// already initialized.
+//
+// Returns true if the hotfix is supported and initialization succeeded, or if
+// it was already initialized; false otherwise.
+bool InitializeCoreAudioDispatchOverride();
+} // namespace media
+
+#endif // MEDIA_AUDIO_MAC_COREAUDIO_DISPATCH_OVERRIDE_H_
diff --git a/chromium/media/audio/mock_audio_manager.cc b/chromium/media/audio/mock_audio_manager.cc
index d05921c846c..74fe7fee7c7 100644
--- a/chromium/media/audio/mock_audio_manager.cc
+++ b/chromium/media/audio/mock_audio_manager.cc
@@ -34,9 +34,6 @@ base::string16 MockAudioManager::GetAudioInputDeviceModel() {
return base::string16();
}
-void MockAudioManager::ShowAudioInputSettings() {
-}
-
void MockAudioManager::GetAudioInputDeviceDescriptions(
AudioDeviceDescriptions* device_descriptions) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
diff --git a/chromium/media/audio/mock_audio_manager.h b/chromium/media/audio/mock_audio_manager.h
index 18cc3c9fb4a..0d7b19e5ecb 100644
--- a/chromium/media/audio/mock_audio_manager.h
+++ b/chromium/media/audio/mock_audio_manager.h
@@ -76,8 +76,6 @@ class MockAudioManager : public AudioManager {
base::string16 GetAudioInputDeviceModel() override;
- void ShowAudioInputSettings() override;
-
void GetAudioInputDeviceDescriptions(
media::AudioDeviceDescriptions* device_descriptions) override;
diff --git a/chromium/media/audio/null_audio_sink.cc b/chromium/media/audio/null_audio_sink.cc
index 151f387e08b..36bc8d18918 100644
--- a/chromium/media/audio/null_audio_sink.cc
+++ b/chromium/media/audio/null_audio_sink.cc
@@ -7,8 +7,8 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
-#include "media/audio/fake_audio_worker.h"
#include "media/base/audio_hash.h"
+#include "media/base/fake_audio_worker.h"
namespace media {
diff --git a/chromium/media/audio/null_audio_sink.h b/chromium/media/audio/null_audio_sink.h
index 84e0263ea3d..9a2eb647d1d 100644
--- a/chromium/media/audio/null_audio_sink.h
+++ b/chromium/media/audio/null_audio_sink.h
@@ -20,8 +20,7 @@ class AudioBus;
class AudioHash;
class FakeAudioWorker;
-class MEDIA_EXPORT NullAudioSink
- : NON_EXPORTED_BASE(public SwitchableAudioRendererSink) {
+class MEDIA_EXPORT NullAudioSink : public SwitchableAudioRendererSink {
public:
NullAudioSink(const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
diff --git a/chromium/media/audio/pulse/audio_manager_pulse.cc b/chromium/media/audio/pulse/audio_manager_pulse.cc
index 6fa330f0e82..8cd8711be09 100644
--- a/chromium/media/audio/pulse/audio_manager_pulse.cc
+++ b/chromium/media/audio/pulse/audio_manager_pulse.cc
@@ -9,9 +9,6 @@
#include "base/logging.h"
#include "base/nix/xdg_util.h"
#include "base/stl_util.h"
-#if defined(USE_ALSA)
-#include "media/audio/alsa/audio_manager_alsa.h"
-#endif
#include "media/audio/audio_device_description.h"
#include "media/audio/pulse/pulse_input.h"
#include "media/audio/pulse/pulse_output.h"
@@ -70,12 +67,6 @@ bool AudioManagerPulse::HasAudioInputDevices() {
return !devices.empty();
}
-void AudioManagerPulse::ShowAudioInputSettings() {
-#if defined(USE_ALSA)
- AudioManagerAlsa::ShowLinuxAudioInputSettings();
-#endif
-}
-
void AudioManagerPulse::GetAudioDeviceNames(
bool input, media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
diff --git a/chromium/media/audio/pulse/audio_manager_pulse.h b/chromium/media/audio/pulse/audio_manager_pulse.h
index bb1d1c08fae..316eec4a534 100644
--- a/chromium/media/audio/pulse/audio_manager_pulse.h
+++ b/chromium/media/audio/pulse/audio_manager_pulse.h
@@ -26,7 +26,6 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
// Implementation of AudioManager.
bool HasAudioOutputDevices() override;
bool HasAudioInputDevices() override;
- void ShowAudioInputSettings() override;
void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
AudioParameters GetInputStreamParameters(
diff --git a/chromium/media/audio/pulse/pulse_input.cc b/chromium/media/audio/pulse/pulse_input.cc
index b27fb65694c..8bf943f1319 100644
--- a/chromium/media/audio/pulse/pulse_input.cc
+++ b/chromium/media/audio/pulse/pulse_input.cc
@@ -10,6 +10,7 @@
#include "media/audio/audio_device_description.h"
#include "media/audio/pulse/audio_manager_pulse.h"
#include "media/audio/pulse/pulse_util.h"
+#include "media/base/audio_timestamp_helper.h"
namespace media {
@@ -270,9 +271,6 @@ void PulseAudioInputStream::StreamNotifyCallback(pa_stream* s,
}
void PulseAudioInputStream::ReadData() {
- uint32_t hardware_delay = pulse::GetHardwareLatencyInBytes(
- handle_, params_.sample_rate(), params_.GetBytesPerFrame());
-
// Update the AGC volume level once every second. Note that,
// |volume| is also updated each time SetVolume() is called
// through IPC by the render-side AGC.
@@ -282,6 +280,14 @@ void PulseAudioInputStream::ReadData() {
GetAgcVolume(&normalized_volume);
normalized_volume = volume_ / GetMaxVolume();
+ // Compensate the audio delay caused by the FIFO.
+ // TODO(dalecurtis): This should probably use pa_stream_get_time() so we can
+ // get the capture time directly.
+ base::TimeTicks capture_time =
+ base::TimeTicks::Now() -
+ (pulse::GetHardwareLatency(handle_) +
+ AudioTimestampHelper::FramesToTime(fifo_.GetAvailableFrames(),
+ params_.sample_rate()));
do {
size_t length = 0;
const void* data = NULL;
@@ -308,12 +314,16 @@ void PulseAudioInputStream::ReadData() {
while (fifo_.available_blocks()) {
const AudioBus* audio_bus = fifo_.Consume();
- // Compensate the audio delay caused by the FIFO.
- hardware_delay += fifo_.GetAvailableFrames() * params_.GetBytesPerFrame();
- callback_->OnData(this, audio_bus, hardware_delay, normalized_volume);
+ callback_->OnData(this, audio_bus, capture_time, normalized_volume);
+
+ // Move the capture time forward for each vended block.
+ capture_time += AudioTimestampHelper::FramesToTime(audio_bus->frames(),
+ params_.sample_rate());
// Sleep 5ms to wait until render consumes the data in order to avoid
// back to back OnData() method.
+ // TODO(dalecurtis): Delete all this. It shouldn't be necessary now that we
+ // have a ring buffer and FIFO on the actual shared memory.,
if (fifo_.available_blocks())
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
}
diff --git a/chromium/media/audio/pulse/pulse_util.cc b/chromium/media/audio/pulse/pulse_util.cc
index 438d4c8d68d..dc7a1882ad2 100644
--- a/chromium/media/audio/pulse/pulse_util.cc
+++ b/chromium/media/audio/pulse/pulse_util.cc
@@ -256,15 +256,6 @@ base::TimeDelta GetHardwareLatency(pa_stream* stream) {
return base::TimeDelta::FromMicroseconds(latency_micros);
}
-int GetHardwareLatencyInBytes(pa_stream* stream,
- int sample_rate,
- int bytes_per_frame) {
- DCHECK(stream);
- return AudioTimestampHelper::TimeToFrames(GetHardwareLatency(stream),
- sample_rate) *
- bytes_per_frame;
-}
-
// Helper macro for CreateInput/OutputStream() to avoid code spam and
// string bloat.
#define RETURN_ON_FAILURE(expression, message) do { \
diff --git a/chromium/media/audio/pulse/pulse_util.h b/chromium/media/audio/pulse/pulse_util.h
index a39ebbfa0ff..2edb432a8d6 100644
--- a/chromium/media/audio/pulse/pulse_util.h
+++ b/chromium/media/audio/pulse/pulse_util.h
@@ -54,10 +54,6 @@ void WaitForOperationCompletion(pa_threaded_mainloop* mainloop,
base::TimeDelta GetHardwareLatency(pa_stream* stream);
-int GetHardwareLatencyInBytes(pa_stream* stream,
- int sample_rate,
- int bytes_per_frame);
-
// Create a recording stream for the threaded mainloop, return true if success,
// otherwise false. |mainloop| and |context| have to be from a valid Pulse
// threaded mainloop and the handle of the created stream will be returned by
diff --git a/chromium/media/audio/sample_rates.cc b/chromium/media/audio/sample_rates.cc
deleted file mode 100644
index 9853ef3aac5..00000000000
--- a/chromium/media/audio/sample_rates.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/audio/sample_rates.h"
-
-#include "base/logging.h"
-
-namespace media {
-
-bool ToAudioSampleRate(int sample_rate, AudioSampleRate* asr) {
- DCHECK(asr);
- switch (sample_rate) {
- case 8000:
- *asr = k8000Hz;
- return true;
- case 16000:
- *asr = k16000Hz;
- return true;
- case 24000:
- *asr = k24000Hz;
- return true;
- case 32000:
- *asr = k32000Hz;
- return true;
- case 48000:
- *asr = k48000Hz;
- return true;
- case 96000:
- *asr = k96000Hz;
- return true;
- case 11025:
- *asr = k11025Hz;
- return true;
- case 22050:
- *asr = k22050Hz;
- return true;
- case 44100:
- *asr = k44100Hz;
- return true;
- case 88200:
- *asr = k88200Hz;
- return true;
- case 176400:
- *asr = k176400Hz;
- return true;
- case 192000:
- *asr = k192000Hz;
- return true;
- case 384000:
- *asr = k384000Hz;
- return true;
- }
- return false;
-}
-
-} // namespace media
diff --git a/chromium/media/audio/sample_rates.h b/chromium/media/audio/sample_rates.h
deleted file mode 100644
index fdc37c26143..00000000000
--- a/chromium/media/audio/sample_rates.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_AUDIO_SAMPLE_RATES_H_
-#define MEDIA_AUDIO_SAMPLE_RATES_H_
-
-#include "media/base/media_export.h"
-
-namespace media {
-
-// Enumeration used for histogramming sample rates into distinct buckets.
-// Logged to UMA, so never reuse a value, always add new/greater ones!
-enum AudioSampleRate {
- k8000Hz = 0,
- k16000Hz = 1,
- k32000Hz = 2,
- k48000Hz = 3,
- k96000Hz = 4,
- k11025Hz = 5,
- k22050Hz = 6,
- k44100Hz = 7,
- k88200Hz = 8,
- k176400Hz = 9,
- k192000Hz = 10,
- k24000Hz = 11,
- k384000Hz = 12,
- // Must always equal the largest value ever reported:
- kAudioSampleRateMax = k384000Hz,
-};
-
-// Helper method to convert integral values to their respective enum values,
-// returns false for unexpected sample rates.
-MEDIA_EXPORT bool ToAudioSampleRate(int sample_rate, AudioSampleRate* asr);
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_SAMPLE_RATES_H_
diff --git a/chromium/media/audio/virtual_audio_input_stream.cc b/chromium/media/audio/virtual_audio_input_stream.cc
index 1252805c0d9..fbe90bbacbc 100644
--- a/chromium/media/audio/virtual_audio_input_stream.cc
+++ b/chromium/media/audio/virtual_audio_input_stream.cc
@@ -111,7 +111,7 @@ void VirtualAudioInputStream::PumpAudio() {
}
// Because the audio is being looped-back, the delay since since it was
// recorded is zero.
- callback_->OnData(this, audio_bus_.get(), 0, 1.0);
+ callback_->OnData(this, audio_bus_.get(), base::TimeTicks::Now(), 1.0);
}
void VirtualAudioInputStream::Close() {
diff --git a/chromium/media/audio/virtual_audio_input_stream.h b/chromium/media/audio/virtual_audio_input_stream.h
index cb5b1a2ca81..b794c382595 100644
--- a/chromium/media/audio/virtual_audio_input_stream.h
+++ b/chromium/media/audio/virtual_audio_input_stream.h
@@ -15,9 +15,9 @@
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "media/audio/audio_io.h"
-#include "media/audio/fake_audio_worker.h"
#include "media/base/audio_converter.h"
#include "media/base/audio_parameters.h"
+#include "media/base/fake_audio_worker.h"
namespace base {
class SingleThreadTaskRunner;
diff --git a/chromium/media/audio/virtual_audio_input_stream_unittest.cc b/chromium/media/audio/virtual_audio_input_stream_unittest.cc
index 14382230c17..8adcffbfee5 100644
--- a/chromium/media/audio/virtual_audio_input_stream_unittest.cc
+++ b/chromium/media/audio/virtual_audio_input_stream_unittest.cc
@@ -37,8 +37,9 @@ class MockInputCallback : public AudioInputStream::AudioInputCallback {
MockInputCallback()
: data_pushed_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
- ON_CALL(*this, OnData(_, _, _, _)).WillByDefault(
- InvokeWithoutArgs(&data_pushed_, &base::WaitableEvent::Signal));
+ ON_CALL(*this, OnData(_, _, _, _))
+ .WillByDefault(
+ InvokeWithoutArgs(&data_pushed_, &base::WaitableEvent::Signal));
}
virtual ~MockInputCallback() {}
@@ -46,7 +47,7 @@ class MockInputCallback : public AudioInputStream::AudioInputCallback {
MOCK_METHOD4(OnData,
void(AudioInputStream* stream,
const AudioBus* source,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume));
MOCK_METHOD1(OnError, void(AudioInputStream* stream));
diff --git a/chromium/media/audio/win/audio_low_latency_input_win.cc b/chromium/media/audio/win/audio_low_latency_input_win.cc
index 60f4865c30a..5d6fc41d27b 100644
--- a/chromium/media/audio/win/audio_low_latency_input_win.cc
+++ b/chromium/media/audio/win/audio_low_latency_input_win.cc
@@ -19,6 +19,7 @@
#include "media/audio/win/core_audio_util_win.h"
#include "media/base/audio_block_fifo.h"
#include "media/base/audio_bus.h"
+#include "media/base/audio_timestamp_helper.h"
#include "media/base/channel_layout.h"
#include "media/base/limits.h"
@@ -90,16 +91,6 @@ WASAPIAudioInputStream::WASAPIAudioInputStream(AudioManagerWin* manager,
// Create the event which will be set in Stop() when capturing shall stop.
stop_capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
DCHECK(stop_capture_event_.IsValid());
-
- ms_to_frame_count_ = static_cast<double>(params.sample_rate()) / 1000.0;
-
- LARGE_INTEGER performance_frequency;
- if (QueryPerformanceFrequency(&performance_frequency)) {
- perf_count_to_100ns_units_ =
- (10000000.0 / static_cast<double>(performance_frequency.QuadPart));
- } else {
- DLOG(ERROR) << "High-resolution performance counters are not supported.";
- }
}
WASAPIAudioInputStream::~WASAPIAudioInputStream() {
@@ -371,7 +362,6 @@ void WASAPIAudioInputStream::Run() {
DVLOG(1) << "AudioBlockFifo buffer count: " << buffers_required;
- LARGE_INTEGER now_count = {};
bool recording = true;
bool error = false;
double volume = GetVolume();
@@ -380,6 +370,8 @@ void WASAPIAudioInputStream::Run() {
base::win::ScopedComPtr<IAudioClock> audio_clock;
audio_client_->GetService(IID_PPV_ARGS(&audio_clock));
+ if (!audio_clock)
+ LOG(WARNING) << "IAudioClock unavailable, capture times may be inaccurate.";
while (recording && !error) {
HRESULT hr = S_FALSE;
@@ -401,28 +393,47 @@ void WASAPIAudioInputStream::Run() {
UINT32 num_frames_to_read = 0;
DWORD flags = 0;
UINT64 device_position = 0;
- UINT64 first_audio_frame_timestamp = 0;
+
+ // Note: The units on this are 100ns intervals. Both GetBuffer() and
+ // GetPosition() will handle the translation from the QPC value, so we
+ // just need to convert from 100ns units into us. Which is just dividing
+ // by 10.0 since 10x100ns = 1us.
+ UINT64 capture_time_100ns = 0;
// Retrieve the amount of data in the capture endpoint buffer,
// replace it with silence if required, create callbacks for each
// packet and store non-delivered data for the next event.
hr = audio_capture_client_->GetBuffer(&data_ptr, &num_frames_to_read,
&flags, &device_position,
- &first_audio_frame_timestamp);
+ &capture_time_100ns);
if (FAILED(hr)) {
DLOG(ERROR) << "Failed to get data from the capture buffer";
continue;
}
+ // TODO(dalecurtis, olka): Is this ever false?
if (audio_clock) {
// The reported timestamp from GetBuffer is not as reliable as the
// clock from the client. We've seen timestamps reported for
// USB audio devices, be off by several days. Furthermore we've
// seen them jump back in time every 2 seconds or so.
- audio_clock->GetPosition(&device_position,
- &first_audio_frame_timestamp);
+ audio_clock->GetPosition(&device_position, &capture_time_100ns);
+ }
+
+ base::TimeTicks capture_time;
+ if (capture_time_100ns) {
+ // See conversion notes on |capture_time_100ns|.
+ capture_time +=
+ base::TimeDelta::FromMicroseconds(capture_time_100ns / 10.0);
+ } else {
+ // We may not have an IAudioClock or GetPosition() may return zero.
+ capture_time = base::TimeTicks::Now();
}
+ // Adjust |capture_time| for the FIFO before pushing.
+ capture_time -= AudioTimestampHelper::FramesToTime(
+ fifo_->GetAvailableFrames(), format_.nSamplesPerSec);
+
if (num_frames_to_read != 0) {
if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
fifo_->PushSilence(num_frames_to_read);
@@ -435,21 +446,6 @@ void WASAPIAudioInputStream::Run() {
hr = audio_capture_client_->ReleaseBuffer(num_frames_to_read);
DLOG_IF(ERROR, FAILED(hr)) << "Failed to release capture buffer";
- // Derive a delay estimate for the captured audio packet.
- // The value contains two parts (A+B), where A is the delay of the
- // first audio frame in the packet and B is the extra delay
- // contained in any stored data. Unit is in audio frames.
- QueryPerformanceCounter(&now_count);
- // first_audio_frame_timestamp will be 0 if we didn't get a timestamp.
- double audio_delay_frames =
- first_audio_frame_timestamp == 0
- ? num_frames_to_read
- : ((perf_count_to_100ns_units_ * now_count.QuadPart -
- first_audio_frame_timestamp) /
- 10000.0) *
- ms_to_frame_count_ +
- fifo_->GetAvailableFrames() - num_frames_to_read;
-
// Get a cached AGC volume level which is updated once every second
// on the audio manager thread. Note that, |volume| is also updated
// each time SetVolume() is called through IPC by the render-side AGC.
@@ -457,7 +453,6 @@ void WASAPIAudioInputStream::Run() {
// Deliver captured data to the registered consumer using a packet
// size which was specified at construction.
- uint32_t delay_frames = static_cast<uint32_t>(audio_delay_frames + 0.5);
while (fifo_->available_blocks()) {
if (converter_) {
if (imperfect_buffer_size_conversion_ &&
@@ -466,18 +461,18 @@ void WASAPIAudioInputStream::Run() {
// convert or else we'll suffer an underrun.
break;
}
- converter_->ConvertWithDelay(delay_frames, convert_bus_.get());
- sink_->OnData(this, convert_bus_.get(), delay_frames * frame_size_,
- volume);
- } else {
- sink_->OnData(this, fifo_->Consume(), delay_frames * frame_size_,
- volume);
- }
+ converter_->Convert(convert_bus_.get());
+ sink_->OnData(this, convert_bus_.get(), capture_time, volume);
- if (delay_frames > packet_size_frames_) {
- delay_frames -= packet_size_frames_;
+ // Move the capture time forward for each vended block.
+ capture_time += AudioTimestampHelper::FramesToTime(
+ convert_bus_->frames(), format_.nSamplesPerSec);
} else {
- delay_frames = 0;
+ sink_->OnData(this, fifo_->Consume(), capture_time, volume);
+
+ // Move the capture time forward for each vended block.
+ capture_time += AudioTimestampHelper::FramesToTime(
+ packet_size_frames_, format_.nSamplesPerSec);
}
}
} break;
@@ -676,7 +671,6 @@ bool WASAPIAudioInputStream::DesiredFormatIsSupported() {
packet_size_frames_ = new_bytes_per_buffer / format_.nBlockAlign;
packet_size_bytes_ = new_bytes_per_buffer;
frame_size_ = format_.nBlockAlign;
- ms_to_frame_count_ = static_cast<double>(format_.nSamplesPerSec) / 1000.0;
imperfect_buffer_size_conversion_ =
std::modf(new_frames_per_buffer, &new_frames_per_buffer) != 0.0;
diff --git a/chromium/media/audio/win/audio_low_latency_input_win.h b/chromium/media/audio/win/audio_low_latency_input_win.h
index 2cb36060994..752c45f905b 100644
--- a/chromium/media/audio/win/audio_low_latency_input_win.h
+++ b/chromium/media/audio/win/audio_low_latency_input_win.h
@@ -188,14 +188,6 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// device role and is not a valid ID as such.
std::string device_id_;
- // Conversion factor used in delay-estimation calculations.
- // Converts a raw performance counter value to 100-nanosecond unit.
- double perf_count_to_100ns_units_ = 0.0;
-
- // Conversion factor used in delay-estimation calculations.
- // Converts from milliseconds to audio frames.
- double ms_to_frame_count_ = 0.0;
-
// Pointer to the object that will receive the recorded audio samples.
AudioInputCallback* sink_ = nullptr;
diff --git a/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc b/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc
index f7ddf9b40b4..e86476b2c2f 100644
--- a/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc
+++ b/chromium/media/audio/win/audio_low_latency_input_win_unittest.cc
@@ -51,7 +51,7 @@ class MockAudioInputCallback : public AudioInputStream::AudioInputCallback {
MOCK_METHOD4(OnData,
void(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume));
MOCK_METHOD1(OnError, void(AudioInputStream* stream));
};
@@ -72,10 +72,9 @@ class FakeAudioInputCallback : public AudioInputStream::AudioInputCallback {
void OnData(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
- EXPECT_GE(hardware_delay_bytes, 0u);
- EXPECT_LT(hardware_delay_bytes, 0xFFFFu); // Arbitrarily picked.
+ EXPECT_GE(capture_time, base::TimeTicks());
num_received_audio_frames_ += src->frames();
data_event_.Signal();
}
@@ -132,7 +131,7 @@ class WriteToFileAudioSink : public AudioInputStream::AudioInputCallback {
// AudioInputStream::AudioInputCallback implementation.
void OnData(AudioInputStream* stream,
const AudioBus* src,
- uint32_t hardware_delay_bytes,
+ base::TimeTicks capture_time,
double volume) override {
EXPECT_EQ(bits_per_sample_, 16);
const int num_samples = src->frames() * src->channels();
diff --git a/chromium/media/audio/win/audio_manager_win.cc b/chromium/media/audio/win/audio_manager_win.cc
index 6b96668c5d3..0443071e91f 100644
--- a/chromium/media/audio/win/audio_manager_win.cc
+++ b/chromium/media/audio/win/audio_manager_win.cc
@@ -16,11 +16,8 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
-#include "base/files/file_path.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
-#include "base/path_service.h"
-#include "base/process/launch.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/win/windows_version.h"
@@ -122,13 +119,7 @@ static int NumberOfWaveOutBuffers() {
return buffers;
}
- // Use 4 buffers for Vista, 3 for everyone else:
- // - The entire Windows audio stack was rewritten for Windows Vista and wave
- // out performance was degraded compared to XP.
- // - The regression was fixed in Windows 7 and most configurations will work
- // with 2, but some (e.g., some Sound Blasters) still need 3.
- // - Some XP configurations (even multi-processor ones) also need 3.
- return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3;
+ return 3;
}
AudioManagerWin::AudioManagerWin(std::unique_ptr<AudioThread> audio_thread,
@@ -243,15 +234,6 @@ base::string16 AudioManagerWin::GetAudioInputDeviceModel() {
return base::string16();
}
-void AudioManagerWin::ShowAudioInputSettings() {
- base::FilePath path;
- PathService::Get(base::DIR_SYSTEM, &path);
- path = path.Append(L"control.exe");
- base::CommandLine command_line(path);
- command_line.AppendArg("mmsys.cpl,,1");
- base::LaunchProcess(command_line, base::LaunchOptions());
-}
-
void AudioManagerWin::GetAudioDeviceNamesImpl(bool input,
AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
diff --git a/chromium/media/audio/win/audio_manager_win.h b/chromium/media/audio/win/audio_manager_win.h
index da15a39f645..3f65fe3d57f 100644
--- a/chromium/media/audio/win/audio_manager_win.h
+++ b/chromium/media/audio/win/audio_manager_win.h
@@ -28,7 +28,6 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
bool HasAudioOutputDevices() override;
bool HasAudioInputDevices() override;
base::string16 GetAudioInputDeviceModel() override;
- void ShowAudioInputSettings() override;
void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
AudioParameters GetInputStreamParameters(
diff --git a/chromium/media/audio/win/audio_output_win_unittest.cc b/chromium/media/audio/win/audio_output_win_unittest.cc
index 8231b11da90..24f0793ce0b 100644
--- a/chromium/media/audio/win/audio_output_win_unittest.cc
+++ b/chromium/media/audio/win/audio_output_win_unittest.cc
@@ -17,7 +17,6 @@
#include "base/sync_socket.h"
#include "base/time/time.h"
#include "base/win/scoped_com_initializer.h"
-#include "base/win/windows_version.h"
#include "media/audio/audio_device_info_accessor_for_tests.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_manager.h"
@@ -452,11 +451,9 @@ TEST_F(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
audio_manager_device_info_->GetDefaultOutputStreamParameters();
int sample_rate = params.sample_rate();
uint32_t samples_10_ms = sample_rate / 100;
- int n = 1;
- (base::win::GetVersion() <= base::win::VERSION_XP) ? n = 5 : n = 1;
AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
- CHANNEL_LAYOUT_MONO, sample_rate, 16, n * samples_10_ms),
+ CHANNEL_LAYOUT_MONO, sample_rate, 16, samples_10_ms),
std::string(), AudioManager::LogCallback());
ASSERT_TRUE(NULL != oas);
diff --git a/chromium/media/audio/win/core_audio_util_win.cc b/chromium/media/audio/win/core_audio_util_win.cc
index 73edb83e7a9..b5871b81416 100644
--- a/chromium/media/audio/win/core_audio_util_win.cc
+++ b/chromium/media/audio/win/core_audio_util_win.cc
@@ -19,7 +19,6 @@
#include "base/win/scoped_handle.h"
#include "base/win/scoped_propvariant.h"
#include "base/win/scoped_variant.h"
-#include "base/win/windows_version.h"
#include "media/audio/audio_device_description.h"
#include "media/base/media_switches.h"
@@ -204,12 +203,6 @@ static bool IsSupportedInternal() {
return false;
}
- // Microsoft does not plan to make the Core Audio APIs available for use
- // with earlier versions of Windows, including Microsoft Windows Server 2003,
- // Windows XP, Windows Millennium Edition, Windows 2000, and Windows 98.
- if (base::win::GetVersion() < base::win::VERSION_VISTA)
- return false;
-
// The audio core APIs are implemented in the Mmdevapi.dll and Audioses.dll
// system components.
// Dependency Walker shows that it is enough to verify possibility to load