summaryrefslogtreecommitdiff
path: root/www/chromium/files/sndio_output.cc
diff options
context:
space:
mode:
authorCarlos J. Puga Medina <cpm@FreeBSD.org>2017-06-27 21:56:39 +0000
committerCarlos J. Puga Medina <cpm@FreeBSD.org>2017-06-27 21:56:39 +0000
commitca28e15b282bd93075ea9b228a1b6b8cd19a5328 (patch)
tree4a38cd12f40aa80ee58c2c01dbe24ab797d648b4 /www/chromium/files/sndio_output.cc
parentwww/iridium: add SNDIO option (diff)
www/chromium: add SNDIO option
PR: 220230 Submitted by: tobik
Notes
Notes: svn path=/head/; revision=444520
Diffstat (limited to 'www/chromium/files/sndio_output.cc')
-rw-r--r--www/chromium/files/sndio_output.cc177
1 files changed, 177 insertions, 0 deletions
diff --git a/www/chromium/files/sndio_output.cc b/www/chromium/files/sndio_output.cc
new file mode 100644
index 000000000000..27c6c1db285a
--- /dev/null
+++ b/www/chromium/files/sndio_output.cc
@@ -0,0 +1,177 @@
+// 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 {
+
+void sndio_onmove(void *arg, int delta) {
+ SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
+
+ self->hw_delay = delta;
+}
+
+void sndio_onvol(void *arg, unsigned int vol) {
+ SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
+
+ self->vol = vol;
+}
+
+void *sndio_threadstart(void *arg) {
+ SndioAudioOutputStream* self = static_cast<SndioAudioOutputStream*>(arg);
+
+ self->RealTimeThread();
+ return NULL;
+}
+
+SndioAudioOutputStream::SndioAudioOutputStream(const AudioParameters& params,
+ AudioManagerBase* manager)
+ : manager(manager),
+ params(params),
+ audio_bus(AudioBus::Create(params)),
+ bytes_per_frame(params.GetBytesPerFrame()),
+ 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 = params.bits_per_sample();
+ 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)params.bits_per_sample() ||
+ 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()];
+ sio_onmove(hdl, sndio_onmove, this);
+ sio_onvol(hdl, sndio_onvol, 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, sndio_threadstart, 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);
+}
+
+void SndioAudioOutputStream::RealTimeThread(void) {
+ int avail, count;
+
+ 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() * 1000);
+ count = source->OnMoreData(delay, base::TimeTicks::Now(), 0, audio_bus.get());
+ audio_bus->ToInterleaved(count, params.bits_per_sample() / 8, buffer);
+ if (count == 0) {
+ // We have to submit something to the device
+ count = audio_bus->frames();
+ memset(buffer, 0, count * params.GetBytesPerFrame());
+ LOG(WARNING) << "No data to play, running empty cycle.";
+ }
+
+ // Submit data to the device
+ avail = count * params.GetBytesPerFrame();
+ count = sio_write(hdl, buffer, avail);
+ if (count == 0) {
+ LOG(WARNING) << "Audio device disconnected.";
+ break;
+ }
+
+ // Update hardware pointer
+ hw_delay += count;
+ }
+}
+
+} // namespace media