887 lines
28 KiB
Diff
887 lines
28 KiB
Diff
diff -Naur chromium-83.0.4103.97.orig/media/BUILD.gn chromium-83.0.4103.97/media/BUILD.gn
|
|
--- a/media/BUILD.gn 2020-06-03 20:40:26.000000000 +0200
|
|
+++ b/media/BUILD.gn 2020-06-13 17:32:28.510395975 +0200
|
|
@@ -65,6 +65,9 @@
|
|
defines += [ "DLOPEN_PULSEAUDIO" ]
|
|
}
|
|
}
|
|
+ if (use_sndio) {
|
|
+ defines += [ "USE_SNDIO" ]
|
|
+ }
|
|
if (use_cras) {
|
|
defines += [ "USE_CRAS" ]
|
|
}
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/BUILD.gn chromium-83.0.4103.97/media/audio/BUILD.gn
|
|
--- a/media/audio/BUILD.gn 2020-06-03 20:39:37.000000000 +0200
|
|
+++ b/media/audio/BUILD.gn 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -236,6 +236,17 @@
|
|
sources += [ "linux/audio_manager_linux.cc" ]
|
|
}
|
|
|
|
+ if (use_sndio) {
|
|
+ libs += [ "sndio" ]
|
|
+ sources += [
|
|
+ "sndio/audio_manager_sndio.cc",
|
|
+ "sndio/sndio_input.cc",
|
|
+ "sndio/sndio_input.h",
|
|
+ "sndio/sndio_output.cc",
|
|
+ "sndio/sndio_output.h"
|
|
+ ]
|
|
+ }
|
|
+
|
|
if (use_alsa) {
|
|
libs += [ "asound" ]
|
|
sources += [
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/linux/audio_manager_linux.cc chromium-83.0.4103.97/media/audio/linux/audio_manager_linux.cc
|
|
--- a/media/audio/linux/audio_manager_linux.cc 2020-06-03 20:39:37.000000000 +0200
|
|
+++ b/media/audio/linux/audio_manager_linux.cc 2020-06-13 18:09:43.623333167 +0200
|
|
@@ -19,6 +19,11 @@
|
|
#include "media/audio/pulse/audio_manager_pulse.h"
|
|
#include "media/audio/pulse/pulse_util.h"
|
|
#endif
|
|
+#if defined(USE_SNDIO)
|
|
+#include "media/audio/sndio/audio_manager_sndio.h"
|
|
+#include "media/audio/sndio/sndio_input.h"
|
|
+#include "media/audio/sndio/sndio_output.h"
|
|
+#endif
|
|
|
|
namespace media {
|
|
|
|
@@ -26,7 +31,8 @@
|
|
kPulse,
|
|
kAlsa,
|
|
kCras,
|
|
- kAudioIOMax = kCras // Must always be equal to largest logged entry.
|
|
+ kSndio,
|
|
+ kAudioIOMax = kSndio // Must always be equal to largest logged entry.
|
|
};
|
|
|
|
std::unique_ptr<media::AudioManager> CreateAudioManager(
|
|
@@ -39,6 +45,16 @@
|
|
audio_log_factory);
|
|
}
|
|
|
|
+#if defined(USE_SNDIO)
|
|
+ struct sio_hdl *hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0);
|
|
+ if (hdl != NULL) {
|
|
+ sio_close(hdl);
|
|
+ UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kSndio, kAudioIOMax + 1);
|
|
+ return std::make_unique<AudioManagerSndio>(std::move(audio_thread),
|
|
+ audio_log_factory);
|
|
+ }
|
|
+#endif
|
|
+
|
|
#if defined(USE_CRAS)
|
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseCras)) {
|
|
UMA_HISTOGRAM_ENUMERATION("Media.LinuxAudioIO", kCras, kAudioIOMax + 1);
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/sndio/audio_manager_sndio.cc chromium-83.0.4103.97/media/audio/sndio/audio_manager_sndio.cc
|
|
--- a/media/audio/sndio/audio_manager_sndio.cc 1970-01-01 01:00:00.000000000 +0100
|
|
+++ b/media/audio/sndio/audio_manager_sndio.cc 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -0,0 +1,148 @@
|
|
+// 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/sndio/audio_manager_sndio.h"
|
|
+
|
|
+#include "base/metrics/histogram_macros.h"
|
|
+#include "base/memory/ptr_util.h"
|
|
+#include "media/audio/audio_device_description.h"
|
|
+#include "media/audio/audio_output_dispatcher.h"
|
|
+#include "media/audio/sndio/sndio_input.h"
|
|
+#include "media/audio/sndio/sndio_output.h"
|
|
+#include "media/base/limits.h"
|
|
+#include "media/base/media_switches.h"
|
|
+
|
|
+namespace media {
|
|
+
|
|
+
|
|
+// Maximum number of output streams that can be open simultaneously.
|
|
+static const int kMaxOutputStreams = 4;
|
|
+
|
|
+// Default sample rate for input and output streams.
|
|
+static const int kDefaultSampleRate = 48000;
|
|
+
|
|
+void AddDefaultDevice(AudioDeviceNames* device_names) {
|
|
+ DCHECK(device_names->empty());
|
|
+ device_names->push_front(AudioDeviceName::CreateDefault());
|
|
+}
|
|
+
|
|
+bool AudioManagerSndio::HasAudioOutputDevices() {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool AudioManagerSndio::HasAudioInputDevices() {
|
|
+ return true;
|
|
+}
|
|
+
|
|
+void AudioManagerSndio::GetAudioInputDeviceNames(
|
|
+ AudioDeviceNames* device_names) {
|
|
+ DCHECK(device_names->empty());
|
|
+ AddDefaultDevice(device_names);
|
|
+}
|
|
+
|
|
+void AudioManagerSndio::GetAudioOutputDeviceNames(
|
|
+ AudioDeviceNames* device_names) {
|
|
+ AddDefaultDevice(device_names);
|
|
+}
|
|
+
|
|
+const char* AudioManagerSndio::GetName() {
|
|
+ return "SNDIO";
|
|
+}
|
|
+
|
|
+AudioParameters AudioManagerSndio::GetInputStreamParameters(
|
|
+ const std::string& device_id) {
|
|
+ static const int kDefaultInputBufferSize = 1024;
|
|
+
|
|
+ int user_buffer_size = GetUserBufferSize();
|
|
+ int buffer_size = user_buffer_size ?
|
|
+ user_buffer_size : kDefaultInputBufferSize;
|
|
+
|
|
+ return AudioParameters(
|
|
+ AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
|
|
+ kDefaultSampleRate, buffer_size);
|
|
+}
|
|
+
|
|
+AudioManagerSndio::AudioManagerSndio(std::unique_ptr<AudioThread> audio_thread,
|
|
+ AudioLogFactory* audio_log_factory)
|
|
+ : AudioManagerBase(std::move(audio_thread),
|
|
+ audio_log_factory) {
|
|
+ DLOG(WARNING) << "AudioManagerSndio";
|
|
+ SetMaxOutputStreamsAllowed(kMaxOutputStreams);
|
|
+}
|
|
+
|
|
+AudioManagerSndio::~AudioManagerSndio() {
|
|
+ Shutdown();
|
|
+}
|
|
+
|
|
+AudioOutputStream* AudioManagerSndio::MakeLinearOutputStream(
|
|
+ const AudioParameters& params,
|
|
+ const LogCallback& log_callback) {
|
|
+ DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
|
|
+ return MakeOutputStream(params);
|
|
+}
|
|
+
|
|
+AudioOutputStream* AudioManagerSndio::MakeLowLatencyOutputStream(
|
|
+ const AudioParameters& params,
|
|
+ const std::string& device_id,
|
|
+ const LogCallback& log_callback) {
|
|
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
|
|
+ DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
|
|
+ return MakeOutputStream(params);
|
|
+}
|
|
+
|
|
+AudioInputStream* AudioManagerSndio::MakeLinearInputStream(
|
|
+ const AudioParameters& params,
|
|
+ const std::string& device_id,
|
|
+ const LogCallback& log_callback) {
|
|
+ DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
|
|
+ return MakeInputStream(params);
|
|
+}
|
|
+
|
|
+AudioInputStream* AudioManagerSndio::MakeLowLatencyInputStream(
|
|
+ const AudioParameters& params,
|
|
+ const std::string& device_id,
|
|
+ const LogCallback& log_callback) {
|
|
+ DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
|
|
+ return MakeInputStream(params);
|
|
+}
|
|
+
|
|
+AudioParameters AudioManagerSndio::GetPreferredOutputStreamParameters(
|
|
+ const std::string& output_device_id,
|
|
+ const AudioParameters& input_params) {
|
|
+ // TODO(tommi): Support |output_device_id|.
|
|
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
|
|
+ static const int kDefaultOutputBufferSize = 2048;
|
|
+
|
|
+ ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
|
|
+ int sample_rate = kDefaultSampleRate;
|
|
+ int buffer_size = kDefaultOutputBufferSize;
|
|
+ if (input_params.IsValid()) {
|
|
+ sample_rate = input_params.sample_rate();
|
|
+ channel_layout = input_params.channel_layout();
|
|
+ buffer_size = std::min(buffer_size, input_params.frames_per_buffer());
|
|
+ }
|
|
+
|
|
+ int user_buffer_size = GetUserBufferSize();
|
|
+ if (user_buffer_size)
|
|
+ buffer_size = user_buffer_size;
|
|
+
|
|
+ return AudioParameters(
|
|
+ AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
|
|
+ sample_rate, buffer_size);
|
|
+}
|
|
+
|
|
+AudioInputStream* AudioManagerSndio::MakeInputStream(
|
|
+ const AudioParameters& params) {
|
|
+ DLOG(WARNING) << "MakeInputStream";
|
|
+ return new SndioAudioInputStream(this,
|
|
+ AudioDeviceDescription::kDefaultDeviceId, params);
|
|
+}
|
|
+
|
|
+AudioOutputStream* AudioManagerSndio::MakeOutputStream(
|
|
+ const AudioParameters& params) {
|
|
+ DLOG(WARNING) << "MakeOutputStream";
|
|
+ return new SndioAudioOutputStream(params, this);
|
|
+}
|
|
+
|
|
+} // namespace media
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/sndio/audio_manager_sndio.h chromium-83.0.4103.97/media/audio/sndio/audio_manager_sndio.h
|
|
--- a/media/audio/sndio/audio_manager_sndio.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ b/media/audio/sndio/audio_manager_sndio.h 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -0,0 +1,65 @@
|
|
+// 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_SNDIO_AUDIO_MANAGER_SNDIO_H_
|
|
+#define MEDIA_AUDIO_SNDIO_AUDIO_MANAGER_SNDIO_H_
|
|
+
|
|
+#include <set>
|
|
+
|
|
+#include "base/compiler_specific.h"
|
|
+#include "base/macros.h"
|
|
+#include "base/memory/ref_counted.h"
|
|
+#include "base/threading/thread.h"
|
|
+#include "media/audio/audio_manager_base.h"
|
|
+
|
|
+namespace media {
|
|
+
|
|
+class MEDIA_EXPORT AudioManagerSndio : public AudioManagerBase {
|
|
+ public:
|
|
+ AudioManagerSndio(std::unique_ptr<AudioThread> audio_thread,
|
|
+ AudioLogFactory* audio_log_factory);
|
|
+ ~AudioManagerSndio() override;
|
|
+
|
|
+ // Implementation of AudioManager.
|
|
+ bool HasAudioOutputDevices() override;
|
|
+ bool HasAudioInputDevices() override;
|
|
+ void GetAudioInputDeviceNames(AudioDeviceNames* device_names) override;
|
|
+ void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) override;
|
|
+ AudioParameters GetInputStreamParameters(
|
|
+ const std::string& device_id) override;
|
|
+ const char* GetName() override;
|
|
+
|
|
+ // Implementation of AudioManagerBase.
|
|
+ AudioOutputStream* MakeLinearOutputStream(
|
|
+ const AudioParameters& params,
|
|
+ const LogCallback& log_callback) override;
|
|
+ AudioOutputStream* MakeLowLatencyOutputStream(
|
|
+ const AudioParameters& params,
|
|
+ const std::string& device_id,
|
|
+ const LogCallback& log_callback) override;
|
|
+ AudioInputStream* MakeLinearInputStream(
|
|
+ const AudioParameters& params,
|
|
+ const std::string& device_id,
|
|
+ const LogCallback& log_callback) override;
|
|
+ AudioInputStream* MakeLowLatencyInputStream(
|
|
+ const AudioParameters& params,
|
|
+ const std::string& device_id,
|
|
+ const LogCallback& log_callback) override;
|
|
+
|
|
+ protected:
|
|
+ AudioParameters GetPreferredOutputStreamParameters(
|
|
+ const std::string& output_device_id,
|
|
+ const AudioParameters& input_params) override;
|
|
+
|
|
+ private:
|
|
+ // Called by MakeLinearOutputStream and MakeLowLatencyOutputStream.
|
|
+ AudioOutputStream* MakeOutputStream(const AudioParameters& params);
|
|
+ AudioInputStream* MakeInputStream(const AudioParameters& params);
|
|
+
|
|
+ DISALLOW_COPY_AND_ASSIGN(AudioManagerSndio);
|
|
+};
|
|
+
|
|
+} // namespace media
|
|
+
|
|
+#endif // MEDIA_AUDIO_SNDIO_AUDIO_MANAGER_SNDIO_H_
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/sndio/sndio_input.cc chromium-83.0.4103.97/media/audio/sndio/sndio_input.cc
|
|
--- a/media/audio/sndio/sndio_input.cc 1970-01-01 01:00:00.000000000 +0100
|
|
+++ b/media/audio/sndio/sndio_input.cc 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -0,0 +1,200 @@
|
|
+// Copyright 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 "base/bind.h"
|
|
+#include "base/logging.h"
|
|
+#include "base/macros.h"
|
|
+#include "media/base/audio_timestamp_helper.h"
|
|
+#include "media/audio/sndio/audio_manager_sndio.h"
|
|
+#include "media/audio/audio_manager.h"
|
|
+#include "media/audio/sndio/sndio_input.h"
|
|
+
|
|
+namespace media {
|
|
+
|
|
+static const SampleFormat kSampleFormat = kSampleFormatS16;
|
|
+
|
|
+void SndioAudioInputStream::OnMoveCallback(void *arg, int delta)
|
|
+{
|
|
+ SndioAudioInputStream* self = static_cast<SndioAudioInputStream*>(arg);
|
|
+
|
|
+ self->hw_delay += delta;
|
|
+}
|
|
+
|
|
+void *SndioAudioInputStream::ThreadEntry(void *arg) {
|
|
+ SndioAudioInputStream* self = static_cast<SndioAudioInputStream*>(arg);
|
|
+
|
|
+ self->ThreadLoop();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+SndioAudioInputStream::SndioAudioInputStream(AudioManagerBase* manager,
|
|
+ const std::string& device_name,
|
|
+ const AudioParameters& params)
|
|
+ : manager(manager),
|
|
+ params(params),
|
|
+ audio_bus(AudioBus::Create(params)),
|
|
+ state(kClosed) {
|
|
+}
|
|
+
|
|
+SndioAudioInputStream::~SndioAudioInputStream() {
|
|
+ if (state != kClosed)
|
|
+ Close();
|
|
+}
|
|
+
|
|
+bool SndioAudioInputStream::Open() {
|
|
+ struct sio_par par;
|
|
+ int sig;
|
|
+
|
|
+ if (state != kClosed)
|
|
+ return false;
|
|
+
|
|
+ if (params.format() != AudioParameters::AUDIO_PCM_LINEAR &&
|
|
+ params.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY) {
|
|
+ LOG(WARNING) << "Unsupported audio format.";
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ sio_initpar(&par);
|
|
+ par.rate = params.sample_rate();
|
|
+ par.rchan = params.channels();
|
|
+ par.bits = SampleFormatToBitsPerChannel(kSampleFormat);
|
|
+ par.bps = par.bits / 8;
|
|
+ par.sig = sig = par.bits != 8 ? 1 : 0;
|
|
+ par.le = SIO_LE_NATIVE;
|
|
+ par.appbufsz = params.frames_per_buffer();
|
|
+
|
|
+ hdl = sio_open(SIO_DEVANY, SIO_REC, 0);
|
|
+
|
|
+ if (hdl == NULL) {
|
|
+ LOG(ERROR) << "Couldn't open audio device.";
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
|
|
+ LOG(ERROR) << "Couldn't set audio parameters.";
|
|
+ goto bad_close;
|
|
+ }
|
|
+
|
|
+ if (par.rate != (unsigned int)params.sample_rate() ||
|
|
+ par.rchan != (unsigned int)params.channels() ||
|
|
+ par.bits != (unsigned int)SampleFormatToBitsPerChannel(kSampleFormat) ||
|
|
+ par.sig != (unsigned int)sig ||
|
|
+ (par.bps > 1 && par.le != SIO_LE_NATIVE) ||
|
|
+ (par.bits != par.bps * 8)) {
|
|
+ LOG(ERROR) << "Unsupported audio parameters.";
|
|
+ goto bad_close;
|
|
+ }
|
|
+ state = kStopped;
|
|
+ buffer = new char[audio_bus->frames() * params.GetBytesPerFrame(kSampleFormat)];
|
|
+ sio_onmove(hdl, &OnMoveCallback, this);
|
|
+ return true;
|
|
+bad_close:
|
|
+ sio_close(hdl);
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void SndioAudioInputStream::Start(AudioInputCallback* cb) {
|
|
+
|
|
+ StartAgc();
|
|
+
|
|
+ state = kRunning;
|
|
+ hw_delay = 0;
|
|
+ callback = cb;
|
|
+ sio_start(hdl);
|
|
+ if (pthread_create(&thread, NULL, &ThreadEntry, this) != 0) {
|
|
+ LOG(ERROR) << "Failed to create real-time thread for recording.";
|
|
+ sio_stop(hdl);
|
|
+ state = kStopped;
|
|
+ }
|
|
+}
|
|
+
|
|
+void SndioAudioInputStream::Stop() {
|
|
+
|
|
+ if (state == kStopped)
|
|
+ return;
|
|
+
|
|
+ state = kStopWait;
|
|
+ pthread_join(thread, NULL);
|
|
+ sio_stop(hdl);
|
|
+ state = kStopped;
|
|
+
|
|
+ StopAgc();
|
|
+}
|
|
+
|
|
+void SndioAudioInputStream::Close() {
|
|
+
|
|
+ if (state == kClosed)
|
|
+ return;
|
|
+
|
|
+ if (state == kRunning)
|
|
+ Stop();
|
|
+
|
|
+ state = kClosed;
|
|
+ delete [] buffer;
|
|
+ sio_close(hdl);
|
|
+
|
|
+ manager->ReleaseInputStream(this);
|
|
+}
|
|
+
|
|
+double SndioAudioInputStream::GetMaxVolume() {
|
|
+ // Not supported
|
|
+ return 0.0;
|
|
+}
|
|
+
|
|
+void SndioAudioInputStream::SetVolume(double volume) {
|
|
+ // Not supported. Do nothing.
|
|
+}
|
|
+
|
|
+double SndioAudioInputStream::GetVolume() {
|
|
+ // Not supported.
|
|
+ return 0.0;
|
|
+}
|
|
+
|
|
+bool SndioAudioInputStream::IsMuted() {
|
|
+ // Not supported.
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void SndioAudioInputStream::SetOutputDeviceForAec(
|
|
+ const std::string& output_device_id) {
|
|
+ // Not supported.
|
|
+}
|
|
+
|
|
+void SndioAudioInputStream::ThreadLoop(void) {
|
|
+ size_t todo, n;
|
|
+ char *data;
|
|
+ unsigned int nframes;
|
|
+ double normalized_volume = 0.0;
|
|
+
|
|
+ nframes = audio_bus->frames();
|
|
+
|
|
+ while (state == kRunning && !sio_eof(hdl)) {
|
|
+
|
|
+ GetAgcVolume(&normalized_volume);
|
|
+
|
|
+ // read one block
|
|
+ todo = nframes * params.GetBytesPerFrame(kSampleFormat);
|
|
+ data = buffer;
|
|
+ while (todo > 0) {
|
|
+ n = sio_read(hdl, data, todo);
|
|
+ if (n == 0)
|
|
+ return; // unrecoverable I/O error
|
|
+ todo -= n;
|
|
+ data += n;
|
|
+ }
|
|
+ hw_delay -= nframes;
|
|
+
|
|
+ // convert frames count to TimeDelta
|
|
+ const base::TimeDelta delay = AudioTimestampHelper::FramesToTime(hw_delay,
|
|
+ params.sample_rate());
|
|
+
|
|
+ // push into bus
|
|
+ audio_bus->FromInterleaved<SignedInt16SampleTypeTraits>(reinterpret_cast<int16_t*>(buffer), nframes);
|
|
+
|
|
+ // invoke callback
|
|
+ callback->OnData(audio_bus.get(), base::TimeTicks::Now() - delay, 1.);
|
|
+ }
|
|
+}
|
|
+
|
|
+} // namespace media
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/sndio/sndio_input.h chromium-83.0.4103.97/media/audio/sndio/sndio_input.h
|
|
--- a/media/audio/sndio/sndio_input.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ b/media/audio/sndio/sndio_input.h 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -0,0 +1,91 @@
|
|
+// Copyright 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_SNDIO_SNDIO_INPUT_H_
|
|
+#define MEDIA_AUDIO_SNDIO_SNDIO_INPUT_H_
|
|
+
|
|
+#include <stdint.h>
|
|
+#include <string>
|
|
+#include <sndio.h>
|
|
+
|
|
+#include "base/compiler_specific.h"
|
|
+#include "base/macros.h"
|
|
+#include "base/memory/weak_ptr.h"
|
|
+#include "base/time/time.h"
|
|
+#include "media/audio/agc_audio_stream.h"
|
|
+#include "media/audio/audio_io.h"
|
|
+#include "media/audio/audio_device_description.h"
|
|
+#include "media/base/audio_parameters.h"
|
|
+
|
|
+namespace media {
|
|
+
|
|
+class AudioManagerBase;
|
|
+
|
|
+// Implementation of AudioOutputStream using sndio(7)
|
|
+class SndioAudioInputStream : public AgcAudioStream<AudioInputStream> {
|
|
+ public:
|
|
+ // Pass this to the constructor if you want to attempt auto-selection
|
|
+ // of the audio recording device.
|
|
+ static const char kAutoSelectDevice[];
|
|
+
|
|
+ // Create a PCM Output stream for the SNDIO device identified by
|
|
+ // |device_name|. If unsure of what to use for |device_name|, use
|
|
+ // |kAutoSelectDevice|.
|
|
+ SndioAudioInputStream(AudioManagerBase* audio_manager,
|
|
+ const std::string& device_name,
|
|
+ const AudioParameters& params);
|
|
+
|
|
+ ~SndioAudioInputStream() override;
|
|
+
|
|
+ // Implementation of AudioInputStream.
|
|
+ bool Open() override;
|
|
+ void Start(AudioInputCallback* callback) override;
|
|
+ void Stop() override;
|
|
+ void Close() override;
|
|
+ double GetMaxVolume() override;
|
|
+ void SetVolume(double volume) override;
|
|
+ double GetVolume() override;
|
|
+ bool IsMuted() override;
|
|
+ void SetOutputDeviceForAec(const std::string& output_device_id) override;
|
|
+
|
|
+ private:
|
|
+
|
|
+ enum StreamState {
|
|
+ kClosed, // Not opened yet
|
|
+ kStopped, // Device opened, but not started yet
|
|
+ kRunning, // Started, device playing
|
|
+ kStopWait // Stopping, waiting for the real-time thread to exit
|
|
+ };
|
|
+
|
|
+ // C-style call-backs
|
|
+ static void OnMoveCallback(void *arg, int delta);
|
|
+ static void* ThreadEntry(void *arg);
|
|
+
|
|
+ // Continuously moves data from the device to the consumer
|
|
+ void ThreadLoop();
|
|
+ // Our creator, the audio manager needs to be notified when we close.
|
|
+ AudioManagerBase* manager;
|
|
+ // Parameters of the source
|
|
+ AudioParameters params;
|
|
+ // We store data here for consumer
|
|
+ std::unique_ptr<AudioBus> audio_bus;
|
|
+ // Call-back that consumes recorded data
|
|
+ AudioInputCallback* callback; // Valid during a recording session.
|
|
+ // Handle of the audio device
|
|
+ struct sio_hdl* hdl;
|
|
+ // Current state of the stream
|
|
+ enum StreamState state;
|
|
+ // High priority thread running ThreadLoop()
|
|
+ pthread_t thread;
|
|
+ // Number of frames buffered in the hardware
|
|
+ int hw_delay;
|
|
+ // Temporary buffer where data is stored sndio-compatible format
|
|
+ char* buffer;
|
|
+
|
|
+ DISALLOW_COPY_AND_ASSIGN(SndioAudioInputStream);
|
|
+};
|
|
+
|
|
+} // namespace media
|
|
+
|
|
+#endif // MEDIA_AUDIO_SNDIO_SNDIO_INPUT_H_
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/sndio/sndio_output.cc chromium-83.0.4103.97/media/audio/sndio/sndio_output.cc
|
|
--- a/media/audio/sndio/sndio_output.cc 1970-01-01 01:00:00.000000000 +0100
|
|
+++ b/media/audio/sndio/sndio_output.cc 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -0,0 +1,183 @@
|
|
+// 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/logging.h"
|
|
+#include "base/time/time.h"
|
|
+#include "base/time/default_tick_clock.h"
|
|
+#include "media/audio/audio_manager_base.h"
|
|
+#include "media/base/audio_timestamp_helper.h"
|
|
+#include "media/audio/sndio/sndio_output.h"
|
|
+
|
|
+namespace media {
|
|
+
|
|
+static const SampleFormat kSampleFormat = kSampleFormatS16;
|
|
+
|
|
+void SndioAudioOutputStream::OnMoveCallback(void *arg, int delta) {
|
|
+ SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
|
|
+
|
|
+ self->hw_delay -= delta;
|
|
+}
|
|
+
|
|
+void SndioAudioOutputStream::OnVolCallback(void *arg, unsigned int vol) {
|
|
+ SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
|
|
+
|
|
+ self->vol = vol;
|
|
+}
|
|
+
|
|
+void *SndioAudioOutputStream::ThreadEntry(void *arg) {
|
|
+ SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
|
|
+
|
|
+ self->ThreadLoop();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+SndioAudioOutputStream::SndioAudioOutputStream(const AudioParameters& params,
|
|
+ AudioManagerBase* manager)
|
|
+ : manager(manager),
|
|
+ params(params),
|
|
+ audio_bus(AudioBus::Create(params)),
|
|
+ state(kClosed),
|
|
+ mutex(PTHREAD_MUTEX_INITIALIZER) {
|
|
+}
|
|
+
|
|
+SndioAudioOutputStream::~SndioAudioOutputStream() {
|
|
+ if (state != kClosed)
|
|
+ Close();
|
|
+}
|
|
+
|
|
+bool SndioAudioOutputStream::Open() {
|
|
+ struct sio_par par;
|
|
+ int sig;
|
|
+
|
|
+ if (params.format() != AudioParameters::AUDIO_PCM_LINEAR &&
|
|
+ params.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY) {
|
|
+ LOG(WARNING) << "Unsupported audio format.";
|
|
+ return false;
|
|
+ }
|
|
+ sio_initpar(&par);
|
|
+ par.rate = params.sample_rate();
|
|
+ par.pchan = params.channels();
|
|
+ par.bits = SampleFormatToBitsPerChannel(kSampleFormat);
|
|
+ par.bps = par.bits / 8;
|
|
+ par.sig = sig = par.bits != 8 ? 1 : 0;
|
|
+ par.le = SIO_LE_NATIVE;
|
|
+ par.appbufsz = params.frames_per_buffer();
|
|
+
|
|
+ hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0);
|
|
+ if (hdl == NULL) {
|
|
+ LOG(ERROR) << "Couldn't open audio device.";
|
|
+ return false;
|
|
+ }
|
|
+ if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) {
|
|
+ LOG(ERROR) << "Couldn't set audio parameters.";
|
|
+ goto bad_close;
|
|
+ }
|
|
+ if (par.rate != (unsigned int)params.sample_rate() ||
|
|
+ par.pchan != (unsigned int)params.channels() ||
|
|
+ par.bits != (unsigned int)SampleFormatToBitsPerChannel(kSampleFormat) ||
|
|
+ par.sig != (unsigned int)sig ||
|
|
+ (par.bps > 1 && par.le != SIO_LE_NATIVE) ||
|
|
+ (par.bits != par.bps * 8)) {
|
|
+ LOG(ERROR) << "Unsupported audio parameters.";
|
|
+ goto bad_close;
|
|
+ }
|
|
+ state = kStopped;
|
|
+ volpending = 0;
|
|
+ vol = 0;
|
|
+ buffer = new char[audio_bus->frames() * params.GetBytesPerFrame(kSampleFormat)];
|
|
+ sio_onmove(hdl, &OnMoveCallback, this);
|
|
+ sio_onvol(hdl, &OnVolCallback, this);
|
|
+ return true;
|
|
+ bad_close:
|
|
+ sio_close(hdl);
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void SndioAudioOutputStream::Close() {
|
|
+ if (state == kClosed)
|
|
+ return;
|
|
+ if (state == kRunning)
|
|
+ Stop();
|
|
+ state = kClosed;
|
|
+ delete [] buffer;
|
|
+ sio_close(hdl);
|
|
+ manager->ReleaseOutputStream(this); // Calls the destructor
|
|
+}
|
|
+
|
|
+void SndioAudioOutputStream::Start(AudioSourceCallback* callback) {
|
|
+ state = kRunning;
|
|
+ hw_delay = 0;
|
|
+ source = callback;
|
|
+ sio_start(hdl);
|
|
+ if (pthread_create(&thread, NULL, &ThreadEntry, this) != 0) {
|
|
+ LOG(ERROR) << "Failed to create real-time thread.";
|
|
+ sio_stop(hdl);
|
|
+ state = kStopped;
|
|
+ }
|
|
+}
|
|
+
|
|
+void SndioAudioOutputStream::Stop() {
|
|
+ if (state == kStopped)
|
|
+ return;
|
|
+ state = kStopWait;
|
|
+ pthread_join(thread, NULL);
|
|
+ sio_stop(hdl);
|
|
+ state = kStopped;
|
|
+}
|
|
+
|
|
+void SndioAudioOutputStream::SetVolume(double v) {
|
|
+ pthread_mutex_lock(&mutex);
|
|
+ vol = v * SIO_MAXVOL;
|
|
+ volpending = 1;
|
|
+ pthread_mutex_unlock(&mutex);
|
|
+}
|
|
+
|
|
+void SndioAudioOutputStream::GetVolume(double* v) {
|
|
+ pthread_mutex_lock(&mutex);
|
|
+ *v = vol * (1. / SIO_MAXVOL);
|
|
+ pthread_mutex_unlock(&mutex);
|
|
+}
|
|
+
|
|
+// This stream is always used with sub second buffer sizes, where it's
|
|
+// sufficient to simply always flush upon Start().
|
|
+void SndioAudioOutputStream::Flush() {}
|
|
+
|
|
+void SndioAudioOutputStream::ThreadLoop(void) {
|
|
+ int avail, count, result;
|
|
+
|
|
+ while (state == kRunning) {
|
|
+ // Update volume if needed
|
|
+ pthread_mutex_lock(&mutex);
|
|
+ if (volpending) {
|
|
+ volpending = 0;
|
|
+ sio_setvol(hdl, vol);
|
|
+ }
|
|
+ pthread_mutex_unlock(&mutex);
|
|
+
|
|
+ // Get data to play
|
|
+ const base::TimeDelta delay = AudioTimestampHelper::FramesToTime(hw_delay,
|
|
+ params.sample_rate());
|
|
+ count = source->OnMoreData(delay, base::TimeTicks::Now(), 0, audio_bus.get());
|
|
+ audio_bus->ToInterleaved<SignedInt16SampleTypeTraits>(count, reinterpret_cast<int16_t*>(buffer));
|
|
+ if (count == 0) {
|
|
+ // We have to submit something to the device
|
|
+ count = audio_bus->frames();
|
|
+ memset(buffer, 0, count * params.GetBytesPerFrame(kSampleFormat));
|
|
+ LOG(WARNING) << "No data to play, running empty cycle.";
|
|
+ }
|
|
+
|
|
+ // Submit data to the device
|
|
+ avail = count * params.GetBytesPerFrame(kSampleFormat);
|
|
+ result = sio_write(hdl, buffer, avail);
|
|
+ if (result == 0) {
|
|
+ LOG(WARNING) << "Audio device disconnected.";
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ // Update hardware pointer
|
|
+ hw_delay += count;
|
|
+ }
|
|
+}
|
|
+
|
|
+} // namespace media
|
|
diff -Naur chromium-83.0.4103.97.orig/media/audio/sndio/sndio_output.h chromium-83.0.4103.97/media/audio/sndio/sndio_output.h
|
|
--- a/media/audio/sndio/sndio_output.h 1970-01-01 01:00:00.000000000 +0100
|
|
+++ b/media/audio/sndio/sndio_output.h 2020-06-13 17:32:28.511395969 +0200
|
|
@@ -0,0 +1,86 @@
|
|
+// 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_SNDIO_SNDIO_OUTPUT_H_
|
|
+#define MEDIA_AUDIO_SNDIO_SNDIO_OUTPUT_H_
|
|
+
|
|
+#include <pthread.h>
|
|
+#include <sndio.h>
|
|
+
|
|
+#include "base/time/tick_clock.h"
|
|
+#include "base/time/time.h"
|
|
+#include "media/audio/audio_io.h"
|
|
+
|
|
+namespace media {
|
|
+
|
|
+class AudioManagerBase;
|
|
+
|
|
+// Implementation of AudioOutputStream using sndio(7)
|
|
+class SndioAudioOutputStream : public AudioOutputStream {
|
|
+ public:
|
|
+ // The manager is creating this object
|
|
+ SndioAudioOutputStream(const AudioParameters& params,
|
|
+ AudioManagerBase* manager);
|
|
+ virtual ~SndioAudioOutputStream();
|
|
+
|
|
+ // Implementation of AudioOutputStream.
|
|
+ bool Open() override;
|
|
+ void Close() override;
|
|
+ void Start(AudioSourceCallback* callback) override;
|
|
+ void Stop() override;
|
|
+ void SetVolume(double volume) override;
|
|
+ void GetVolume(double* volume) override;
|
|
+ void Flush() override;
|
|
+
|
|
+ friend void sndio_onmove(void *arg, int delta);
|
|
+ friend void sndio_onvol(void *arg, unsigned int vol);
|
|
+ friend void *sndio_threadstart(void *arg);
|
|
+
|
|
+ private:
|
|
+ enum StreamState {
|
|
+ kClosed, // Not opened yet
|
|
+ kStopped, // Device opened, but not started yet
|
|
+ kRunning, // Started, device playing
|
|
+ kStopWait // Stopping, waiting for the real-time thread to exit
|
|
+ };
|
|
+
|
|
+ // C-style call-backs
|
|
+ static void OnMoveCallback(void *arg, int delta);
|
|
+ static void OnVolCallback(void *arg, unsigned int vol);
|
|
+ static void* ThreadEntry(void *arg);
|
|
+
|
|
+ // Continuously moves data from the producer to the device
|
|
+ void ThreadLoop(void);
|
|
+
|
|
+ // Our creator, the audio manager needs to be notified when we close.
|
|
+ AudioManagerBase* manager;
|
|
+ // Parameters of the source
|
|
+ AudioParameters params;
|
|
+ // Source stores data here
|
|
+ std::unique_ptr<AudioBus> audio_bus;
|
|
+ // Call-back that produces data to play
|
|
+ AudioSourceCallback* source;
|
|
+ // Handle of the audio device
|
|
+ struct sio_hdl* hdl;
|
|
+ // Current state of the stream
|
|
+ enum StreamState state;
|
|
+ // High priority thread running ThreadLoop()
|
|
+ pthread_t thread;
|
|
+ // Protects vol, volpending and hw_delay
|
|
+ pthread_mutex_t mutex;
|
|
+ // Current volume in the 0..SIO_MAXVOL range
|
|
+ int vol;
|
|
+ // Set to 1 if volumes must be refreshed in the realtime thread
|
|
+ int volpending;
|
|
+ // Number of frames buffered in the hardware
|
|
+ int hw_delay;
|
|
+ // Temporary buffer where data is stored sndio-compatible format
|
|
+ char* buffer;
|
|
+
|
|
+ DISALLOW_COPY_AND_ASSIGN(SndioAudioOutputStream);
|
|
+};
|
|
+
|
|
+} // namespace media
|
|
+
|
|
+#endif // MEDIA_AUDIO_SNDIO_SNDIO_OUTPUT_H_
|
|
diff -Naur chromium-83.0.4103.97.orig/media/media_options.gni chromium-83.0.4103.97/media/media_options.gni
|
|
--- a/media/media_options.gni 2020-06-03 20:40:26.000000000 +0200
|
|
+++ b/media/media_options.gni 2020-06-13 17:32:28.512395963 +0200
|
|
@@ -119,6 +119,9 @@
|
|
# Enables runtime selection of ALSA library for audio.
|
|
use_alsa = false
|
|
|
|
+ # Enable runtime selection of sndio(7)
|
|
+ use_sndio = false
|
|
+
|
|
# Alsa should be used on non-Android, non-Mac POSIX systems.
|
|
# Alsa should be used on desktop Chromecast and audio-only Chromecast builds.
|
|
if (is_posix && !is_android && !is_mac &&
|