svn commit: r506266 - head/www/chromium/files
Carlos J. Puga Medina
cpm at FreeBSD.org
Tue Jul 9 08:20:58 UTC 2019
Author: cpm
Date: Tue Jul 9 08:20:56 2019
New Revision: 506266
URL: https://svnweb.freebsd.org/changeset/ports/506266
Log:
www/chromium: Add support for audio recording using sndio
PR: 238869
Submitted by: Zielonka Michal <zielonka.michal at gmail.com>, tobik
Obtained from: https://github.com/t6/freebsd-ports-sndio/commit/f213ba25a3460ed6f8e858f04f5592fca8edb7d8
MFH: 2019Q3
Modified:
head/www/chromium/files/sndio_input.cc
head/www/chromium/files/sndio_input.h
head/www/chromium/files/sndio_output.cc
head/www/chromium/files/sndio_output.h
Modified: head/www/chromium/files/sndio_input.cc
==============================================================================
--- head/www/chromium/files/sndio_input.cc Tue Jul 9 04:02:26 2019 (r506265)
+++ head/www/chromium/files/sndio_input.cc Tue Jul 9 08:20:56 2019 (r506266)
@@ -2,169 +2,200 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/audio/sndio/sndio_input.h"
-
-#include <stddef.h>
-
#include "base/bind.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "media/base/audio_timestamp_helper.h"
#include "media/audio/openbsd/audio_manager_openbsd.h"
#include "media/audio/audio_manager.h"
+#include "media/audio/sndio/sndio_input.h"
namespace media {
static const SampleFormat kSampleFormat = kSampleFormatS16;
-void sndio_in_onmove(void *arg, int delta) {
- NOTIMPLEMENTED();
+void SndioAudioInputStream::OnMoveCallback(void *arg, int delta)
+{
SndioAudioInputStream* self = static_cast<SndioAudioInputStream*>(arg);
- self->hw_delay_ = delta - self->params_.GetBytesPerFrame(kSampleFormat);
+ self->hw_delay += delta;
}
-void *sndio_in_threadstart(void *arg) {
- NOTIMPLEMENTED();
+void *SndioAudioInputStream::ThreadEntry(void *arg) {
SndioAudioInputStream* self = static_cast<SndioAudioInputStream*>(arg);
- self->ReadAudio();
+ self->ThreadLoop();
return NULL;
}
-SndioAudioInputStream::SndioAudioInputStream(AudioManagerBase* audio_manager,
- const std::string& device_name,
- const AudioParameters& params)
- : audio_manager_(audio_manager),
- device_name_(device_name),
- params_(params),
- bytes_per_buffer_(params.GetBytesPerBuffer(kSampleFormat)),
- buffer_duration_(base::TimeDelta::FromMicroseconds(
- params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
- static_cast<float>(params.sample_rate()))),
- callback_(NULL),
- device_handle_(NULL),
- read_callback_behind_schedule_(false),
- audio_bus_(AudioBus::Create(params)) {
+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() {}
+SndioAudioInputStream::~SndioAudioInputStream() {
+ if (state != kClosed)
+ Close();
+}
bool SndioAudioInputStream::Open() {
struct sio_par par;
int sig;
- if (device_handle_)
- return false; // Already open.
+ if (state != kClosed)
+ return false;
- if (params_.format() != AudioParameters::AUDIO_PCM_LINEAR &&
- params_.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY) {
+ 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 = SampleFormatToBytesPerChannel(kSampleFormat);
+ 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();
- sndio_rec_bufsz_ = par.bufsz;
- sndio_rec_bufsize_ = par.round * par.bps * par.rchan;
+ par.appbufsz = params.frames_per_buffer();
- device_handle_ = sio_open(SIO_DEVANY, SIO_REC, 0);
+ hdl = sio_open(SIO_DEVANY, SIO_REC, 0);
- if (device_handle_ == NULL) {
+ if (hdl == NULL) {
LOG(ERROR) << "Couldn't open audio device.";
return false;
}
- if (!sio_setpar(device_handle_, &par) || !sio_getpar(device_handle_, &par)) {
+ 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)SampleFormatToBytesPerChannel(kSampleFormat) ||
+ 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;
}
- sio_onmove(device_handle_, sndio_in_onmove, this);
-
- audio_buffer_.reset(new uint8_t[bytes_per_buffer_]);
-
+ state = kStopped;
+ buffer = new char[audio_bus->frames() * params.GetBytesPerFrame(kSampleFormat)];
+ sio_onmove(hdl, &OnMoveCallback, this);
return true;
bad_close:
- sio_close(device_handle_);
+ sio_close(hdl);
return false;
}
-void SndioAudioInputStream::Start(AudioInputCallback* callback) {
- DCHECK(!callback_ && callback);
- callback_ = callback;
+void SndioAudioInputStream::Start(AudioInputCallback* cb) {
+
StartAgc();
- // We start reading data half |buffer_duration_| later than when the
- // buffer might have got filled, to accommodate some delays in the audio
- // driver. This could also give us a smooth read sequence going forward.
- base::TimeDelta delay = buffer_duration_ + buffer_duration_ / 2;
- next_read_time_ = base::TimeTicks::Now() + delay;
- if (pthread_create(&thread_, NULL, sndio_in_threadstart, this) != 0)
- LOG(ERROR) << "Failed to create real-time thread.";
+ 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::ReadAudio() {
- NOTIMPLEMENTED();
-}
-
void SndioAudioInputStream::Stop() {
- if (!device_handle_ || !callback_)
+
+ if (state == kStopped)
return;
- StopAgc();
+ state = kStopWait;
+ pthread_join(thread, NULL);
+ sio_stop(hdl);
+ state = kStopped;
- pthread_join(thread_, NULL);
- sio_stop(device_handle_);
-
- callback_ = NULL;
+ StopAgc();
}
void SndioAudioInputStream::Close() {
- if (device_handle_) {
- sio_close(device_handle_);
- audio_buffer_.reset();
- device_handle_ = NULL;
- }
- audio_manager_->ReleaseInputStream(this);
+ if (state == kClosed)
+ return;
+
+ if (state == kRunning)
+ Stop();
+
+ state = kClosed;
+ delete [] buffer;
+ sio_close(hdl);
+
+ manager->ReleaseInputStream(this);
}
double SndioAudioInputStream::GetMaxVolume() {
- return static_cast<double>(SIO_MAXVOL);
+ // Not supported
+ return 0.0;
}
void SndioAudioInputStream::SetVolume(double volume) {
- NOTIMPLEMENTED();
+ // Not supported. Do nothing.
}
double SndioAudioInputStream::GetVolume() {
- long current_volume = 0;
- return static_cast<double>(current_volume);
+ // Not supported.
+ return 0.0;
}
bool SndioAudioInputStream::IsMuted() {
+ // Not supported.
return false;
}
void SndioAudioInputStream::SetOutputDeviceForAec(
const std::string& output_device_id) {
-// Not supported. Do nothing.
+ // 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() * 1000);
+
+ // push into bus
+ audio_bus->FromInterleaved(buffer, nframes, SampleFormatToBytesPerChannel(kSampleFormat));
+
+ // invoke callback
+ callback->OnData(audio_bus.get(), base::TimeTicks::Now() - delay, 1.);
+ }
}
} // namespace media
Modified: head/www/chromium/files/sndio_input.h
==============================================================================
--- head/www/chromium/files/sndio_input.h Tue Jul 9 04:02:26 2019 (r506265)
+++ head/www/chromium/files/sndio_input.h Tue Jul 9 08:20:56 2019 (r506266)
@@ -22,19 +22,7 @@ namespace media {
class AudioManagerBase;
-// call-backs invoked from C libraries, thus requiring C linkage
-extern "C" {
- // Invoked (on the real-time thread) at each sound card clock tick
- void sndio_in_onmove(void *arg, int delta);
- // Invoked (on the real-time thread) whenever the volume changes
- void sndio_in_onvol(void *arg, unsigned int vol);
- // Real-time thread entry point
- void *sndio_in_threadstart(void *arg);
-}
-
-// Provides an input stream for audio capture based on the SNDIO PCM interface.
-// This object is not thread safe and all methods should be invoked in the
-// thread that created the object.
+// Implementation of AudioOutputStream using sndio(7)
class SndioAudioInputStream : public AgcAudioStream<AudioInputStream> {
public:
// Pass this to the constructor if you want to attempt auto-selection
@@ -61,45 +49,39 @@ class SndioAudioInputStream : public AgcAudioStream<Au
bool IsMuted() override;
void SetOutputDeviceForAec(const std::string& output_device_id) override;
- // C-linkage call-backs are friends to access private data
- friend void sndio_in_onmove(void *arg, int delta);
- friend void sndio_in_onvol(void *arg, unsigned int vol);
- friend void *sndio_in_threadstart(void *arg);
-
private:
- // Logs the error and invokes any registered callbacks.
- void HandleError(const char* method, int error);
- // Reads one or more buffers of audio from the device, passes on to the
- // registered callback and schedules the next read.
- void ReadAudio();
+ 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
+ };
- // Recovers from any device errors if possible.
- bool Recover(int error);
+ // C-style call-backs
+ static void OnMoveCallback(void *arg, int delta);
+ static void* ThreadEntry(void *arg);
- // Non-refcounted pointer back to the audio manager.
- // The AudioManager indirectly holds on to stream objects, so we don't
- // want circular references. Additionally, stream objects live on the audio
- // thread, which is owned by the audio manager and we don't want to addref
- // the manager from that thread.
- AudioManagerBase* audio_manager_;
- std::string device_name_;
- AudioParameters params_;
- int bytes_per_buffer_;
- base::TimeDelta buffer_duration_; // Length of each recorded buffer.
- AudioInputCallback* callback_; // Valid during a recording session.
- base::TimeTicks next_read_time_; // Scheduled time for next read callback.
- struct sio_hdl* device_handle_; // Handle to the SNDIO PCM recording device.
- std::unique_ptr<uint8_t[]> audio_buffer_; // Buffer used for reading audio data.
- bool read_callback_behind_schedule_;
- std::unique_ptr<AudioBus> audio_bus_;
-
- int hw_delay_;
- int sndio_rec_bufsize_;
- int sndio_rec_bufsz_;
-
- // High priority thread running RealTimeThread()
- pthread_t thread_;
+ // 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);
};
Modified: head/www/chromium/files/sndio_output.cc
==============================================================================
--- head/www/chromium/files/sndio_output.cc Tue Jul 9 04:02:26 2019 (r506265)
+++ head/www/chromium/files/sndio_output.cc Tue Jul 9 08:20:56 2019 (r506266)
@@ -13,22 +13,22 @@ namespace media {
static const SampleFormat kSampleFormat = kSampleFormatS16;
-void sndio_onmove(void *arg, int delta) {
+void SndioAudioOutputStream::OnMoveCallback(void *arg, int delta) {
SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
- self->hw_delay = delta;
+ self->hw_delay -= delta;
}
-void sndio_onvol(void *arg, unsigned int vol) {
+void SndioAudioOutputStream::OnVolCallback(void *arg, unsigned int vol) {
SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
self->vol = vol;
}
-void *sndio_threadstart(void *arg) {
+void *SndioAudioOutputStream::ThreadEntry(void *arg) {
SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
- self->RealTimeThread();
+ self->ThreadLoop();
return NULL;
}
@@ -37,7 +37,6 @@ SndioAudioOutputStream::SndioAudioOutputStream(const A
: manager(manager),
params(params),
audio_bus(AudioBus::Create(params)),
- bytes_per_frame(params.GetBytesPerFrame(kSampleFormat)),
state(kClosed),
mutex(PTHREAD_MUTEX_INITIALIZER) {
}
@@ -87,8 +86,8 @@ bool SndioAudioOutputStream::Open() {
volpending = 0;
vol = 0;
buffer = new char[audio_bus->frames() * params.GetBytesPerFrame(kSampleFormat)];
- sio_onmove(hdl, sndio_onmove, this);
- sio_onvol(hdl, sndio_onvol, this);
+ sio_onmove(hdl, &OnMoveCallback, this);
+ sio_onvol(hdl, &OnVolCallback, this);
return true;
bad_close:
sio_close(hdl);
@@ -111,7 +110,7 @@ void SndioAudioOutputStream::Start(AudioSourceCallback
hw_delay = 0;
source = callback;
sio_start(hdl);
- if (pthread_create(&thread, NULL, sndio_threadstart, this) != 0) {
+ if (pthread_create(&thread, NULL, &ThreadEntry, this) != 0) {
LOG(ERROR) << "Failed to create real-time thread.";
sio_stop(hdl);
state = kStopped;
@@ -140,7 +139,7 @@ void SndioAudioOutputStream::GetVolume(double* v) {
pthread_mutex_unlock(&mutex);
}
-void SndioAudioOutputStream::RealTimeThread(void) {
+void SndioAudioOutputStream::ThreadLoop(void) {
int avail, count;
while (state == kRunning) {
Modified: head/www/chromium/files/sndio_output.h
==============================================================================
--- head/www/chromium/files/sndio_output.h Tue Jul 9 04:02:26 2019 (r506265)
+++ head/www/chromium/files/sndio_output.h Tue Jul 9 08:20:56 2019 (r506266)
@@ -12,22 +12,10 @@
#include "base/time/time.h"
#include "media/audio/audio_io.h"
-
namespace media {
-class AudioParameters;
class AudioManagerBase;
-// call-backs invoked from C libraries, thus requiring C linkage
-extern "C" {
- // Invoked (on the real-time thread) at each sound card clock tick
- void sndio_onmove(void *arg, int delta);
- // Invoked (on the real-time thread) whenever the volume changes
- void sndio_onvol(void *arg, unsigned int vol);
- // Real-time thread entry point
- void *sndio_threadstart(void *arg);
-}
-
// Implementation of AudioOutputStream using sndio(7)
class SndioAudioOutputStream : public AudioOutputStream {
public:
@@ -37,14 +25,13 @@ class SndioAudioOutputStream : public AudioOutputStrea
virtual ~SndioAudioOutputStream();
// Implementation of AudioOutputStream.
- virtual bool Open() override;
- virtual void Close() override;
- virtual void Start(AudioSourceCallback* callback) override;
- virtual void Stop() override;
- virtual void SetVolume(double volume) override;
- virtual void GetVolume(double* volume) override;
+ bool Open() override;
+ void Close() override;
+ void Start(AudioSourceCallback* callback) override;
+ void Stop() override;
+ void SetVolume(double volume) override;
+ void GetVolume(double* volume) override;
- // C-linkage call-backs are friends to access private data
friend void sndio_onmove(void *arg, int delta);
friend void sndio_onvol(void *arg, unsigned int vol);
friend void *sndio_threadstart(void *arg);
@@ -56,22 +43,28 @@ class SndioAudioOutputStream : public AudioOutputStrea
kRunning, // Started, device playing
kStopWait // Stopping, waiting for the real-time thread to exit
};
- // Continuously moves data from the audio bus to the device
- void RealTimeThread(void);
+
+ // 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;
- int bytes_per_frame;
// 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 RealTimeThread()
+ // High priority thread running ThreadLoop()
pthread_t thread;
// Protects vol, volpending and hw_delay
pthread_mutex_t mutex;
@@ -79,7 +72,7 @@ class SndioAudioOutputStream : public AudioOutputStrea
int vol;
// Set to 1 if volumes must be refreshed in the realtime thread
int volpending;
- // Number of bytes buffered in the hardware
+ // Number of frames buffered in the hardware
int hw_delay;
// Temporary buffer where data is stored sndio-compatible format
char* buffer;
More information about the svn-ports-all
mailing list