From owner-svn-ports-head@freebsd.org Tue Jul 9 08:20:58 2019 Return-Path: Delivered-To: svn-ports-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 2E48615D37CA; Tue, 9 Jul 2019 08:20:58 +0000 (UTC) (envelope-from cpm@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id CEA4C85A2C; Tue, 9 Jul 2019 08:20:57 +0000 (UTC) (envelope-from cpm@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A94662511B; Tue, 9 Jul 2019 08:20:57 +0000 (UTC) (envelope-from cpm@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x698KvB6072349; Tue, 9 Jul 2019 08:20:57 GMT (envelope-from cpm@FreeBSD.org) Received: (from cpm@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x698Ku40072345; Tue, 9 Jul 2019 08:20:56 GMT (envelope-from cpm@FreeBSD.org) Message-Id: <201907090820.x698Ku40072345@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: cpm set sender to cpm@FreeBSD.org using -f From: "Carlos J. Puga Medina" Date: Tue, 9 Jul 2019 08:20:56 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r506266 - head/www/chromium/files X-SVN-Group: ports-head X-SVN-Commit-Author: cpm X-SVN-Commit-Paths: head/www/chromium/files X-SVN-Commit-Revision: 506266 X-SVN-Commit-Repository: ports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: CEA4C85A2C X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.93 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.93)[-0.934,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] X-BeenThere: svn-ports-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the ports tree for head List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Jul 2019 08:20:58 -0000 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 , 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 - #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(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(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(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(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(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 { public: // Pass this to the constructor if you want to attempt auto-selection @@ -61,45 +49,39 @@ class SndioAudioInputStream : public AgcAudioStream audio_buffer_; // Buffer used for reading audio data. - bool read_callback_behind_schedule_; - std::unique_ptr 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 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(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(arg); self->vol = vol; } -void *sndio_threadstart(void *arg) { +void *SndioAudioOutputStream::ThreadEntry(void *arg) { SndioAudioOutputStream* self = static_cast(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 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;