diff options
Diffstat (limited to 'mail/thunderbird45/patches/patch-mozilla_media_libcubeb_src_cubeb__oss.c')
-rw-r--r-- | mail/thunderbird45/patches/patch-mozilla_media_libcubeb_src_cubeb__oss.c | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/mail/thunderbird45/patches/patch-mozilla_media_libcubeb_src_cubeb__oss.c b/mail/thunderbird45/patches/patch-mozilla_media_libcubeb_src_cubeb__oss.c new file mode 100644 index 00000000000..90770318478 --- /dev/null +++ b/mail/thunderbird45/patches/patch-mozilla_media_libcubeb_src_cubeb__oss.c @@ -0,0 +1,407 @@ +$NetBSD: patch-mozilla_media_libcubeb_src_cubeb__oss.c,v 1.1 2017/04/27 13:38:19 ryoon Exp $ + +--- mozilla/media/libcubeb/src/cubeb_oss.c.orig 2016-04-17 13:47:46.296872813 +0000 ++++ mozilla/media/libcubeb/src/cubeb_oss.c +@@ -0,0 +1,402 @@ ++/* ++ * Copyright © 2014 Mozilla Foundation ++ * ++ * This program is made available under an ISC-style license. See the ++ * accompanying file LICENSE for details. ++ */ ++#if defined(HAVE_SYS_SOUNDCARD_H) ++#include <sys/soundcard.h> ++#else ++#include <soundcard.h> ++#endif ++#include <unistd.h> ++#include <stdlib.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++#include <sys/ioctl.h> ++#include <errno.h> ++#include <pthread.h> ++#include <stdio.h> ++ ++#include "cubeb/cubeb.h" ++#include "cubeb-internal.h" ++ ++#ifndef CUBEB_OSS_DEFAULT_OUTPUT ++#define CUBEB_OSS_DEFAULT_OUTPUT "/dev/dsp" ++#endif ++ ++#define OSS_BUFFER_SIZE 1024 ++ ++struct cubeb { ++ struct cubeb_ops const * ops; ++}; ++ ++struct cubeb_stream { ++ cubeb * context; ++ ++ cubeb_data_callback data_callback; ++ cubeb_state_callback state_callback; ++ void * user_ptr; ++ float volume; ++ float panning; ++ ++ pthread_mutex_t state_mutex; ++ pthread_cond_t state_cond; ++ ++ int running; ++ int stopped; ++ int floating; ++ ++ /* These two vars are needed to support old versions of OSS */ ++ unsigned int position_bytes; ++ unsigned int last_position_bytes; ++ ++ uint64_t written_frags; /* The number of fragments written to /dev/dsp */ ++ uint64_t missed_frags; /* fragments output with stopped stream */ ++ ++ cubeb_stream_params params; ++ int fd; ++ pthread_t th; ++}; ++ ++static struct cubeb_ops const oss_ops; ++ ++int oss_init(cubeb ** context, char const * context_name) ++{ ++ cubeb* ctx = (cubeb*)malloc(sizeof(cubeb)); ++ ctx->ops = &oss_ops; ++ *context = ctx; ++ return CUBEB_OK; ++} ++ ++static void oss_destroy(cubeb *ctx) ++{ ++ free(ctx); ++} ++ ++static char const * oss_get_backend_id(cubeb * context) ++{ ++ static char oss_name[] = "oss"; ++ return oss_name; ++} ++ ++static int oss_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) ++{ ++ *max_channels = 2; /* Let's support only stereo for now */ ++ return CUBEB_OK; ++} ++ ++static int oss_get_min_latency(cubeb * context, cubeb_stream_params params, ++ uint32_t * latency_ms) ++{ ++ /* 40ms is a big enough number to work ok */ ++ *latency_ms = 40; ++ return CUBEB_OK; ++} ++ ++static int oss_get_preferred_sample_rate(cubeb *context, uint32_t * rate) ++{ ++ /* 48000 seems a prefered choice for most audio devices ++ * and a good choice for OSS */ ++ *rate = 48000; ++ return CUBEB_OK; ++} ++ ++static void run_state_callback(cubeb_stream *stream, cubeb_state state) ++{ ++ if (stream->state_callback) { ++ stream->state_callback(stream, stream->user_ptr, state); ++ } ++} ++ ++static long run_data_callback(cubeb_stream *stream, void *buffer, long nframes) ++{ ++ long got = 0; ++ pthread_mutex_lock(&stream->state_mutex); ++ if (stream->data_callback && stream->running && !stream->stopped) { ++ pthread_mutex_unlock(&stream->state_mutex); ++ got = stream->data_callback(stream, stream->user_ptr, buffer, nframes); ++ } else { ++ pthread_mutex_unlock(&stream->state_mutex); ++ } ++ return got; ++} ++ ++static void apply_volume(int16_t* buffer, unsigned int n, ++ float volume, float panning) ++{ ++ float left = volume; ++ float right = volume; ++ unsigned int i; ++ int pan[2]; ++ if (panning<0) { ++ right *= (1+panning); ++ } else { ++ left *= (1-panning); ++ } ++ pan[0] = 128.0*left; ++ pan[1] = 128.0*right; ++ for(i=0; i<n; i++){ ++ buffer[i] = ((int)buffer[i])*pan[i%2]/128; ++ } ++} ++ ++static void *writer(void *stm) ++{ ++ cubeb_stream* stream = (cubeb_stream*)stm; ++ int16_t buffer[OSS_BUFFER_SIZE]; ++ float f_buffer[OSS_BUFFER_SIZE]; ++ int got; ++ unsigned long i; ++ while (stream->running) { ++ pthread_mutex_lock(&stream->state_mutex); ++ if (stream->stopped) { ++ pthread_mutex_unlock(&stream->state_mutex); ++ run_state_callback(stream, CUBEB_STATE_STOPPED); ++ pthread_mutex_lock(&stream->state_mutex); ++ while (stream->stopped) { ++ pthread_cond_wait(&stream->state_cond, &stream->state_mutex); ++ } ++ pthread_mutex_unlock(&stream->state_mutex); ++ run_state_callback(stream, CUBEB_STATE_STARTED); ++ continue; ++ } ++ pthread_mutex_unlock(&stream->state_mutex); ++ if (stream->floating) { ++ got = run_data_callback(stream, f_buffer, ++ OSS_BUFFER_SIZE/stream->params.channels); ++ for (i=0; i<((unsigned long)got)*stream->params.channels; i++) { ++ buffer[i] = f_buffer[i]*32767.0; ++ } ++ } else { ++ got = run_data_callback(stream, buffer, ++ OSS_BUFFER_SIZE/stream->params.channels); ++ } ++ apply_volume(buffer, got*stream->params.channels, ++ stream->volume, stream->panning); ++ if (got<0) { ++ run_state_callback(stream, CUBEB_STATE_ERROR); ++ break; ++ } ++ if (!got) { ++ run_state_callback(stream, CUBEB_STATE_DRAINED); ++ } ++ if (got) { ++ size_t i = 0; ++ size_t s = got*stream->params.channels*sizeof(int16_t); ++ while (i < s) { ++ ssize_t n = write(stream->fd, ((char*)buffer) + i, s - i); ++ if (n<=0) { ++ run_state_callback(stream, CUBEB_STATE_ERROR); ++ break; ++ } ++ i+=n; ++ } ++ stream->written_frags+=got; ++ } ++ } ++ return NULL; ++} ++ ++static void oss_try_set_latency(cubeb_stream* stream, unsigned int latency) ++{ ++ unsigned int latency_bytes, n_frag; ++ int frag; ++ /* fragment size of 1024 is a good choice with good chances to be accepted */ ++ unsigned int frag_size=1024; ++ unsigned int frag_log=10; /* 2^frag_log = frag_size */ ++ latency_bytes = ++ latency*stream->params.rate*stream->params.channels*sizeof(uint16_t)/1000; ++ n_frag = latency_bytes>>frag_log; ++ frag = (n_frag<<16) | frag_log; ++ /* Even if this fails we wish to continue, not checking for errors */ ++ ioctl(stream->fd, SNDCTL_DSP_SETFRAGMENT, &frag); ++} ++ ++static int oss_stream_init(cubeb * context, cubeb_stream ** stm, ++ char const * stream_name, ++ cubeb_stream_params stream_params, ++ unsigned int latency, ++ cubeb_data_callback data_callback, ++ cubeb_state_callback state_callback, void * user_ptr) ++{ ++ cubeb_stream* stream = (cubeb_stream*)malloc(sizeof(cubeb_stream)); ++ stream->context = context; ++ stream->data_callback = data_callback; ++ stream->state_callback = state_callback; ++ stream->user_ptr = user_ptr; ++ ++ if ((stream->fd = open(CUBEB_OSS_DEFAULT_OUTPUT, O_WRONLY)) == -1) { ++ free(stream); ++ return CUBEB_ERROR; ++ } ++#define SET(what, to) do { unsigned int i = to; \ ++ int j = ioctl(stream->fd, what, &i); \ ++ if (j == -1 || i != to) { \ ++ close(stream->fd); \ ++ free(stream); \ ++ return CUBEB_ERROR_INVALID_FORMAT; } } while (0) ++ ++ stream->params = stream_params; ++ stream->volume = 1.0; ++ stream->panning = 0.0; ++ ++ oss_try_set_latency(stream, latency); ++ ++ stream->floating = 0; ++ SET(SNDCTL_DSP_CHANNELS, stream_params.channels); ++ SET(SNDCTL_DSP_SPEED, stream_params.rate); ++ switch (stream_params.format) { ++ case CUBEB_SAMPLE_S16LE: ++ SET(SNDCTL_DSP_SETFMT, AFMT_S16_LE); ++ break; ++ case CUBEB_SAMPLE_S16BE: ++ SET(SNDCTL_DSP_SETFMT, AFMT_S16_BE); ++ break; ++ case CUBEB_SAMPLE_FLOAT32LE: ++ SET(SNDCTL_DSP_SETFMT, AFMT_S16_NE); ++ stream->floating = 1; ++ break; ++ default: ++ close(stream->fd); ++ free(stream); ++ return CUBEB_ERROR; ++ } ++ ++ ++ pthread_mutex_init(&stream->state_mutex, NULL); ++ pthread_cond_init(&stream->state_cond, NULL); ++ ++ stream->running = 1; ++ stream->stopped = 1; ++ stream->position_bytes = 0; ++ stream->last_position_bytes = 0; ++ stream->written_frags = 0; ++ stream->missed_frags = 0; ++ ++ pthread_create(&stream->th, NULL, writer, (void*)stream); ++ ++ *stm = stream; ++ ++ return CUBEB_OK; ++} ++ ++static void oss_stream_destroy(cubeb_stream * stream) ++{ ++ pthread_mutex_lock(&stream->state_mutex); ++ ++ stream->running = 0; ++ stream->stopped = 0; ++ pthread_cond_signal(&stream->state_cond); ++ ++ pthread_mutex_unlock(&stream->state_mutex); ++ ++ pthread_join(stream->th, NULL); ++ ++ pthread_mutex_destroy(&stream->state_mutex); ++ pthread_cond_destroy(&stream->state_cond); ++ close(stream->fd); ++ free(stream); ++} ++ ++static int oss_stream_get_latency(cubeb_stream * stream, uint32_t * latency) ++{ ++ if (ioctl(stream->fd, SNDCTL_DSP_GETODELAY, latency)==-1) { ++ return CUBEB_ERROR; ++ } ++ /* Convert latency from bytes to frames */ ++ *latency /= stream->params.channels*sizeof(int16_t); ++ return CUBEB_OK; ++} ++ ++ ++static int oss_stream_current_optr(cubeb_stream * stream, uint64_t * position) ++{ ++ count_info ci; ++ /* Unfortunately, this ioctl is only available in OSS 4.x */ ++#ifdef SNDCTL_DSP_CURRENT_OPTR ++ oss_count_t count; ++ if (ioctl(stream->fd, SNDCTL_DSP_CURRENT_OPTR, &count) != -1) { ++ *position = count.samples;// + count.fifo_samples; ++ return CUBEB_OK; ++ } ++#endif ++ /* Fall back to this ioctl in case the previous one fails */ ++ if (ioctl(stream->fd, SNDCTL_DSP_GETOPTR, &ci) == -1) { ++ return CUBEB_ERROR; ++ } ++ /* ci.bytes is only 32 bit and will start to wrap after arithmetic overflow */ ++ stream->position_bytes += ci.bytes - stream->last_position_bytes; ++ stream->last_position_bytes = ci.bytes; ++ *position = stream->position_bytes/stream->params.channels/sizeof(int16_t); ++ return CUBEB_OK; ++} ++ ++static int oss_stream_get_position(cubeb_stream * stream, uint64_t * position) ++{ ++ if ( oss_stream_current_optr(stream, position) == CUBEB_OK ){ ++ *position -= stream->missed_frags; ++ return CUBEB_OK; ++ } ++ /* If no correct method to get position works we resort to this */ ++ *position = stream->written_frags; ++ return CUBEB_OK; ++} ++ ++ ++static int oss_stream_start(cubeb_stream * stream) ++{ ++ pthread_mutex_lock(&stream->state_mutex); ++ if (stream->stopped) { ++ uint64_t ptr; ++ oss_stream_current_optr(stream, &ptr); ++ stream->missed_frags = ptr - stream->written_frags; ++ stream->stopped = 0; ++ pthread_cond_signal(&stream->state_cond); ++ } ++ pthread_mutex_unlock(&stream->state_mutex); ++ return CUBEB_OK; ++} ++ ++static int oss_stream_stop(cubeb_stream * stream) ++{ ++ pthread_mutex_lock(&stream->state_mutex); ++ stream->stopped = 1; ++ pthread_mutex_unlock(&stream->state_mutex); ++ return CUBEB_OK; ++} ++ ++int oss_stream_set_panning(cubeb_stream * stream, float panning) ++{ ++ if (stream->params.channels == 2) { ++ stream->panning=panning; ++ } ++ return CUBEB_OK; ++} ++ ++int oss_stream_set_volume(cubeb_stream * stream, float volume) ++{ ++ stream->volume=volume; ++ return CUBEB_OK; ++} ++ ++static struct cubeb_ops const oss_ops = { ++ .init = oss_init, ++ .get_backend_id = oss_get_backend_id, ++ .get_max_channel_count = oss_get_max_channel_count, ++ .get_min_latency = oss_get_min_latency, ++ .get_preferred_sample_rate = oss_get_preferred_sample_rate, ++ .destroy = oss_destroy, ++ .stream_init = oss_stream_init, ++ .stream_destroy = oss_stream_destroy, ++ .stream_start = oss_stream_start, ++ .stream_stop = oss_stream_stop, ++ .stream_get_position = oss_stream_get_position, ++ .stream_get_latency = oss_stream_get_latency, ++ .stream_set_volume = oss_stream_set_volume, ++ .stream_set_panning = oss_stream_set_panning, ++ .stream_get_current_device = NULL, ++ .stream_device_destroy = NULL, ++ .stream_register_device_changed_callback = NULL ++}; |