diff --git a/media/libsydneyaudio/src/sydney_audio_sunaudio.c b/media/libsydneyaudio/src/sydney_audio_sunaudio.c index cbd97d8924a..77b85778eeb 100644 --- a/media/libsydneyaudio/src/sydney_audio_sunaudio.c +++ b/media/libsydneyaudio/src/sydney_audio_sunaudio.c @@ -15,7 +15,8 @@ * Copyright (C) 2008 Sun Microsystems, Inc., * Brian Lu * - * Contributor(s): + * Contributor(s): + * Ginn Chen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -31,55 +32,101 @@ * * ***** END LICENSE BLOCK ***** * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "sydney_audio.h" -#define DEFAULT_AUDIO_DEVICE "/dev/audio" +/* Sun Audio implementation based heavily on sydney_audio_mac.c */ -#define LOOP_WHILE_EINTR(v,func) do { (v) = (func); } \ - while ((v) == -1 && errno == EINTR); +#define DEFAULT_AUDIO_DEVICE "/dev/audio" +#define DEFAULT_DSP_DEVICE "/dev/dsp" + +/* Macros copied from audio_oss.h */ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (C) 4Front Technologies 1996-2008. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#define OSSIOCPARM_MASK 0x1fff /* parameters must be < 8192 bytes */ +#define OSSIOC_VOID 0x00000000 /* no parameters */ +#define OSSIOC_OUT 0x20000000 /* copy out parameters */ +#define OSSIOC_IN 0x40000000 /* copy in parameters */ +#define OSSIOC_INOUT (OSSIOC_IN|OSSIOC_OUT) +#define OSSIOC_SZ(t) ((sizeof (t) & OSSIOCPARM_MASK) << 16) +#define __OSSIO(x, y) ((int)(OSSIOC_VOID|(x<<8)|y)) +#define __OSSIOR(x, y, t) ((int)(OSSIOC_OUT|OSSIOC_SZ(t)|(x<<8)|y)) +#define __OSSIOWR(x, y, t) ((int)(OSSIOC_INOUT|OSSIOC_SZ(t)|(x<<8)|y)) +#define SNDCTL_DSP_SPEED __OSSIOWR('P', 2, int) +#define SNDCTL_DSP_CHANNELS __OSSIOWR('P', 6, int) +#define SNDCTL_DSP_SETFMT __OSSIOWR('P', 5, int) /* Selects ONE fmt */ +#define SNDCTL_DSP_GETPLAYVOL __OSSIOR('P', 24, int) +#define SNDCTL_DSP_SETPLAYVOL __OSSIOWR('P', 24, int) +#define SNDCTL_DSP_HALT_OUTPUT __OSSIO('P', 34) +#define AFMT_S16_LE 0x00000010 +#define AFMT_S16_BE 0x00000020 +#ifdef SA_LITTLE_ENDIAN +#define AFMT_S16_NE AFMT_S16_LE +#else +#define AFMT_S16_NE AFMT_S16_BE +#endif typedef struct sa_buf sa_buf; struct sa_buf { - unsigned int size; /* the size of data */ - sa_buf *next; - unsigned char data[]; /* sound data */ + unsigned int size; + unsigned int start; + unsigned int end; + sa_buf * next; + unsigned char data[]; }; -struct sa_stream -{ - int audio_fd; - pthread_mutex_t mutex; +struct sa_stream { + bool using_oss; + int output_fd; pthread_t thread_id; - int playing; + pthread_mutex_t mutex; + bool playing; int64_t bytes_played; /* audio format info */ - /* default setting */ - unsigned int default_n_channels; - unsigned int default_rate; - unsigned int default_precision; - - /* used settings */ unsigned int rate; unsigned int n_channels; - unsigned int precision; + unsigned int bytes_per_ch; /* buffer list */ - sa_buf *bl_head; - sa_buf *bl_tail; + sa_buf * bl_head; + sa_buf * bl_tail; + int n_bufs; }; /* Use a default buffer size with enough room for one second of audio, @@ -87,10 +134,15 @@ struct sa_stream * a generous limit on the number of buffers. */ #define BUF_SIZE (2 * 44100 * 4) +#define BUF_LIMIT 5 -static void* audio_callback(void* s); +#if BUF_LIMIT < 2 +#error BUF_LIMIT must be at least 2! +#endif -static sa_buf *new_buffer(int size); +static void *audio_callback(void *s); +static sa_buf *new_buffer(void); +static int shutdown_device(sa_stream_t *s); /* * ----------------------------------------------------------------------------- @@ -106,163 +158,181 @@ sa_stream_create_pcm( sa_pcm_format_t format, unsigned int rate, unsigned int n_channels -) -{ - sa_stream_t * s = 0; - - /* Make sure we return a NULL stream pointer on failure. */ - if (_s == NULL) +) { + /* + * Make sure we return a NULL stream pointer on failure. + */ + if (_s == NULL) { return SA_ERROR_INVALID; - + } *_s = NULL; - if (mode != SA_MODE_WRONLY) + if (mode != SA_MODE_WRONLY) { return SA_ERROR_NOT_SUPPORTED; - - if (format != SA_PCM_FORMAT_S16_LE) + } + if (format != SA_PCM_FORMAT_S16_NE) { return SA_ERROR_NOT_SUPPORTED; + } /* * Allocate the instance and required resources. */ - if ((s = malloc(sizeof(sa_stream_t))) == NULL) + sa_stream_t *s; + if ((s = malloc(sizeof(sa_stream_t))) == NULL) { return SA_ERROR_OOM; - + } + if ((s->bl_head = new_buffer()) == NULL) { + free(s); + return SA_ERROR_SYSTEM; + } if (pthread_mutex_init(&s->mutex, NULL) != 0) { + free(s->bl_head); free(s); return SA_ERROR_SYSTEM; } - s->audio_fd = NULL; - s->rate = rate; - s->n_channels = n_channels; - s->precision = 16; - - s->playing = 0; - s->bytes_played = 0; - s->bl_tail = s->bl_head = NULL; + s->output_fd = -1; + s->playing = false; + s->bytes_played = 0; + s->rate = rate; + s->n_channels = n_channels; + s->bytes_per_ch = 2; + s->bl_tail = s->bl_head; + s->n_bufs = 1; *_s = s; - return SA_SUCCESS; } - int -sa_stream_open(sa_stream_t *s) -{ - int fd,err; - audio_info_t audio_info; - char *device_name; - - /* according to the sun audio manual (man audio(7I)) - * use the device name set in AUDIODEV - * environment variaible if it is set - */ - device_name = getenv("AUDIODEV"); - if (!device_name) - device_name = DEFAULT_AUDIO_DEVICE; - - if (s == NULL) +sa_stream_open(sa_stream_t *s) { + if (s == NULL) { return SA_ERROR_NO_INIT; - - if (s->audio_fd != NULL) + } + if (s->output_fd != -1) { return SA_ERROR_INVALID; - - fd = open(device_name,O_WRONLY | O_NONBLOCK); - if (fd >= 0) - { - close (fd); - fd = open (device_name, O_WRONLY); } - if ( fd < 0 ) + /* + * Open the default audio output unit. + */ + + /* If UTAUDIODEV is set, use it with Sun Audio interface */ + char * sa_device_name = getenv("UTAUDIODEV"); + char * dsp_device_name = NULL; + if (!sa_device_name) { + dsp_device_name = getenv("AUDIODSP"); + if (!dsp_device_name) { + dsp_device_name = DEFAULT_DSP_DEVICE; + } + sa_device_name = getenv("AUDIODEV"); + if (!sa_device_name) { + sa_device_name = DEFAULT_AUDIO_DEVICE; + } + } + + int fd = -1; + s->using_oss = false; + /* Try to use OSS if available */ + if (dsp_device_name) { + fd = open(dsp_device_name, O_WRONLY, 0); + if (fd >= 0) { + s->using_oss = true; + } + } + + /* Try Sun Audio */ + if (!s->using_oss) { + fd = open(sa_device_name, O_WRONLY | O_NONBLOCK); + } + + if (fd < 0) { - printf("Open %s failed:%s ",device_name,strerror(errno)); + printf("Open %s failed:%s.\n", sa_device_name, strerror(errno)); return SA_ERROR_NO_DEVICE; } - - AUDIO_INITINFO(&audio_info); - // save the default settings for resetting - err = ioctl(fd, AUDIO_GETINFO, &audio_info); - if (err == -1) - { - perror("ioctl AUDIO_GETINFO failed"); - close(fd); - return SA_ERROR_SYSTEM; + if (s->using_oss) { + /* set the playback rate */ + if (ioctl(fd, SNDCTL_DSP_SPEED, &(s->rate)) < 0) { + close(fd); + return SA_ERROR_NOT_SUPPORTED; + } + + /* set the channel numbers */ + if (ioctl(fd, SNDCTL_DSP_CHANNELS, &(s->n_channels)) < 0) { + close(fd); + return SA_ERROR_NOT_SUPPORTED; + } + + int format = AFMT_S16_NE; + if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) < 0) { + close(fd); + return SA_ERROR_NOT_SUPPORTED; + } + + s->output_fd = fd; + return SA_SUCCESS; } - s->default_n_channels = audio_info.play.channels; - s->default_rate = audio_info.play.sample_rate; - s->default_precision = audio_info.play.precision; - + audio_info_t audio_info; AUDIO_INITINFO(&audio_info) - audio_info.play.sample_rate = s->rate; - audio_info.play.channels = s->n_channels; - audio_info.play.precision = s->precision; + audio_info.play.channels = s->n_channels; + audio_info.play.precision = s->bytes_per_ch * 8; /* Signed Linear PCM encoding */ audio_info.play.encoding = AUDIO_ENCODING_LINEAR; - err=ioctl(fd,AUDIO_SETINFO,&audio_info); - if (err== -1) - return SA_ERROR_NOT_SUPPORTED; - - AUDIO_INITINFO(&audio_info) - err=ioctl(fd,AUDIO_GETINFO,&audio_info); - if (err== -1) - { - perror("ioctl AUDIO_SETINFO failed"); + if (ioctl(fd, AUDIO_SETINFO, &audio_info) == -1) { + printf("ioctl AUDIO_SETINFO failed.\n"); + close(fd); return SA_ERROR_NOT_SUPPORTED; } - s->audio_fd = fd; - + s->output_fd = fd; return SA_SUCCESS; } int -sa_stream_destroy(sa_stream_t *s) -{ - int result; - - if (s == NULL) +sa_stream_destroy(sa_stream_t *s) { + if (s == NULL) { return SA_SUCCESS; - - - pthread_mutex_lock(&s->mutex); - - result = SA_SUCCESS; + } /* - * Shut down the audio output device. - * and release resources + * Join the thread. */ - if (s->audio_fd != NULL) - { - if (close(s->audio_fd) < 0) - { - perror("Close sun audio fd failed"); - result = SA_ERROR_SYSTEM; - } + bool thread_created = false; + pthread_mutex_lock(&s->mutex); + if (s->playing) { + thread_created = true; + s->playing = false; } - - s->thread_id = 0; - - while (s->bl_head != NULL) { - sa_buf * next = s->bl_head->next; - free(s->bl_head); - s->bl_head = next; - } - pthread_mutex_unlock(&s->mutex); + if (thread_created) { + pthread_join(s->thread_id, NULL); + } + int result = SA_SUCCESS; + + + /* + * Shutdown the audio output device. + */ + result = shutdown_device(s); + + /* + * Release resouces. + */ if (pthread_mutex_destroy(&s->mutex) != 0) { result = SA_ERROR_SYSTEM; } - + while (s->bl_head != NULL) { + sa_buf * next = s->bl_head->next; + free(s->bl_head); + s->bl_head = next; + } free(s); return result; @@ -275,94 +345,140 @@ sa_stream_destroy(sa_stream_t *s) */ int -sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) -{ - - int result; - sa_buf *buf; - - if (s == NULL || s->audio_fd == NULL) +sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) { + if (s == NULL || s->output_fd == -1) { return SA_ERROR_NO_INIT; - - if (nbytes == 0) + } + if (nbytes == 0) { return SA_SUCCESS; - - - /* - * Append the new data to the end of our buffer list. - */ - result = SA_SUCCESS; - buf = new_buffer(nbytes); - - if (buf == NULL) - return SA_ERROR_OOM; - - memcpy(buf->data,data, nbytes); + } pthread_mutex_lock(&s->mutex); - if (!s->bl_head) - s->bl_head = buf; - else - s->bl_tail->next = buf; - s->bl_tail = buf; + /* + * Append the new data to the end of our buffer list. + */ + int result = SA_SUCCESS; + while (1) { + unsigned int avail = s->bl_tail->size - s->bl_tail->end; - pthread_mutex_unlock(&s->mutex); + if (nbytes <= avail) { + /* + * The new data will fit into the current tail buffer, so + * just copy it in and we're done. + */ + memcpy(s->bl_tail->data + s->bl_tail->end, data, nbytes); + s->bl_tail->end += nbytes; + break; - /* - * Once we have our first block of audio data, enable the audio callback - * function. This doesn't need to be protected by the mutex, because - * s->playing is not used in the audio callback thread, and it's probably - * better not to be inside the lock when we enable the audio callback. - */ + } else { + /* + * Copy what we can into the tail and allocate a new buffer + * for the rest. + */ + memcpy(s->bl_tail->data + s->bl_tail->end, data, avail); + s->bl_tail->end += avail; + data = ((unsigned char *)data) + avail; + nbytes -= avail; + + /* + * If we still have data left to copy but we've hit the limit of + * allowable buffer allocations, we need to spin for a bit to allow + * the audio callback function to slurp some more data up. + */ + if (nbytes > 0 && s->n_bufs == BUF_LIMIT) { +#ifdef TIMING_TRACE + printf("#"); /* too much audio data */ +#endif + if (!s->playing) { + /* + * We haven't even started playing yet! That means the + * BUF_SIZE/BUF_LIMIT values are too low... Not much we can + * do here; spinning won't help because the audio callback + * hasn't been enabled yet. Oh well, error time. + */ + printf("Too much audio data received before audio device enabled!\n"); + result = SA_ERROR_SYSTEM; + break; + } + while (s->n_bufs == BUF_LIMIT) { + pthread_mutex_unlock(&s->mutex); + struct timespec ts = {0, 1000000}; + nanosleep(&ts, NULL); + pthread_mutex_lock(&s->mutex); + } + } + + /* + * Allocate a new tail buffer, and go 'round again to fill it up. + */ + if ((s->bl_tail->next = new_buffer()) == NULL) { + result = SA_ERROR_OOM; + break; + } + s->n_bufs++; + s->bl_tail = s->bl_tail->next; + + } /* if (nbytes <= avail), else */ + + } /* while (1) */ + + /* + * Once we have our first block of audio data, enable the audio callback + * function. + */ if (!s->playing) { - s->playing = 1; + s->playing = true; if (pthread_create(&s->thread_id, NULL, audio_callback, s) != 0) { result = SA_ERROR_SYSTEM; } - } + } + + pthread_mutex_unlock(&s->mutex); return result; } -static void* -audio_callback(void* data) -{ - sa_stream_t* s = (sa_stream_t*)data; - sa_buf *buf; - int fd,nbytes_written,bytes,nbytes; +static void * +audio_callback(void *data) { + sa_stream_t *s = data; - fd = s->audio_fd; - - while (1) - { - if (s->thread_id == 0) - break; - - pthread_mutex_lock(&s->mutex); - while (s->bl_head) - { - buf = s->bl_head; - s->bl_head = s->bl_head->next; - - nbytes_written = 0; - nbytes = buf->size; - - while (nbytes_written < nbytes) - { - LOOP_WHILE_EINTR(bytes,(write(fd, (void *)((buf->data)+nbytes_written), nbytes-nbytes_written))); - - nbytes_written += bytes; - if (nbytes_written != nbytes) - printf("SunAudio\tWrite completed short - %d vs %d. Write more data\n",nbytes_written,nbytes); + pthread_mutex_lock(&s->mutex); + while (s->playing) { + /* + * Consume data from the start of the buffer list. + */ + while (s->output_fd != -1) { + unsigned int avail = s->bl_head->end - s->bl_head->start; + if (avail > 0) { + int written = write(s->output_fd, s->bl_head->data + s->bl_head->start, avail); + if (written == -1) { + break; /* Try again later. */ + } + s->bl_head->start += written; + s->bytes_played += written; + if (written < avail) { + break; + } } - free(buf); - s->bytes_played += nbytes; - } - pthread_mutex_unlock(&s->mutex); - } - + sa_buf * next = s->bl_head->next; + if (next == NULL) { +#ifdef TIMING_TRACE + printf("!"); /* not enough audio data */ +#endif + break; + } + free(s->bl_head); + s->bl_head = next; + s->n_bufs--; + } /* while (s->output_fd != -1) */ + pthread_mutex_unlock(&s->mutex); + struct timespec ts = {0, 1000000}; + nanosleep(&ts, NULL); + pthread_mutex_lock(&s->mutex); + } /* s->playing */ + pthread_mutex_unlock(&s->mutex); return NULL; } @@ -373,20 +489,23 @@ audio_callback(void* data) */ int -sa_stream_get_write_size(sa_stream_t *s, size_t *size) -{ - sa_buf * b; - size_t used = 0; - - if (s == NULL ) +sa_stream_get_write_size(sa_stream_t *s, size_t *size) { + if (s == NULL || s->output_fd == -1) { return SA_ERROR_NO_INIT; + } - /* there is no interface to get the avaiable writing buffer size - * in sun audio, we return max size here to force sa_stream_write() to - * be called when there is data to be played + pthread_mutex_lock(&s->mutex); + + /* + * The sum of the free space in the tail buffer plus the size of any new + * buffers represents the write space available before blocking. */ - *size = BUF_SIZE; + unsigned int avail = s->bl_tail->size - s->bl_tail->end; + avail += (BUF_LIMIT - s->n_bufs) * BUF_SIZE; + *size = avail; + + pthread_mutex_unlock(&s->mutex); return SA_SUCCESS; } @@ -396,9 +515,8 @@ sa_stream_get_write_size(sa_stream_t *s, size_t *size) */ int -sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) -{ - if (s == NULL) { +sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) { + if (s == NULL || s->output_fd == -1) { return SA_ERROR_NO_INIT; } if (position != SA_POSITION_WRITE_SOFTWARE) { @@ -411,17 +529,106 @@ sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) return SA_SUCCESS; } +int +sa_stream_drain(sa_stream_t *s) { + if (s == NULL || s->output_fd == -1) { + return SA_ERROR_NO_INIT; + } + + while (1) { + pthread_mutex_lock(&s->mutex); + sa_buf * b; + size_t used = 0; + for (b = s->bl_head; b != NULL; b = b->next) { + used += b->end - b->start; + } + pthread_mutex_unlock(&s->mutex); + + if (used == 0) { + break; + } + + struct timespec ts = {0, 1000000}; + nanosleep(&ts, NULL); + } + return SA_SUCCESS; +} + +int +sa_stream_pause(sa_stream_t *s) { + if (s == NULL || s->output_fd == -1) { + return SA_ERROR_NO_INIT; + } + + if (s->using_oss) { + return SA_ERROR_NOT_SUPPORTED; + } + + int result = SA_SUCCESS; + + pthread_mutex_lock(&s->mutex); + result = shutdown_device(s); + if (result == SA_SUCCESS) { + s->output_fd = -1; + } + pthread_mutex_unlock(&s->mutex); + + return result; +} + + +int +sa_stream_resume(sa_stream_t *s) { + if (s == NULL) { + return SA_ERROR_NO_INIT; + } + + if (s->using_oss) { + return SA_ERROR_NOT_SUPPORTED; + } + + pthread_mutex_lock(&s->mutex); + int result = sa_stream_open(s); + pthread_mutex_unlock(&s->mutex); + + return result; +} + static sa_buf * -new_buffer(int size) -{ - sa_buf * b = malloc(sizeof(sa_buf) + size); +new_buffer(void) { + sa_buf * b = malloc(sizeof(sa_buf) + BUF_SIZE); if (b != NULL) { - b->size = size; + b->size = BUF_SIZE; + b->start = 0; + b->end = 0; b->next = NULL; } return b; } +static int +shutdown_device(sa_stream_t *s) { + if (s->output_fd != -1) + { + /* Flush buffer. */ + if (s->using_oss) { + ioctl(s->output_fd, SNDCTL_DSP_HALT_OUTPUT); + } else { + ioctl(s->output_fd, I_FLUSH); + } + + if (close(s->output_fd) < 0) + { + return SA_ERROR_SYSTEM; + } + } + return SA_SUCCESS; +} + +/* + * ----------------------------------------------------------------------------- + * Startup and shutdown functions + * ----------------------------------------------------------------------------- /* * ----------------------------------------------------------------------------- * Extension functions @@ -429,25 +636,35 @@ new_buffer(int size) */ int -sa_stream_set_volume_abs(sa_stream_t *s, float vol) -{ - unsigned int newVolume = 0; - int err; - audio_info_t audio_info; +sa_stream_set_volume_abs(sa_stream_t *s, float vol) { + if (s == NULL || s->output_fd == -1) { + return SA_ERROR_NO_INIT; + } + if (s->using_oss) { + int mvol = ((int)(100 * vol)) | ((int)(100 * vol) << 8); + if (ioctl(s->output_fd, SNDCTL_DSP_SETPLAYVOL, &mvol) < 0) { + return SA_ERROR_SYSTEM; + } + return SA_SUCCESS; + } - newVolume = (AUDIO_MAX_GAIN-AUDIO_MIN_GAIN)*vol+AUDIO_MIN_GAIN; + unsigned int newVolume = (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN) * vol + AUDIO_MIN_GAIN; /* Check if the new volume is valid or not */ if ( newVolume < AUDIO_MIN_GAIN || newVolume > AUDIO_MAX_GAIN ) return SA_ERROR_INVALID; + pthread_mutex_lock(&s->mutex); + audio_info_t audio_info; AUDIO_INITINFO(&audio_info); audio_info.play.gain = newVolume; - err=ioctl(s->audio_fd,AUDIO_SETINFO,&audio_info); // The actual setting of the parameters + int err = ioctl(s->output_fd, AUDIO_SETINFO, &audio_info); + pthread_mutex_unlock(&s->mutex); + if (err == -1) { - perror("sa_stream_set_volume_abs failed") ; + perror("sa_stream_set_volume_abs failed\n"); return SA_ERROR_SYSTEM; } @@ -455,27 +672,33 @@ sa_stream_set_volume_abs(sa_stream_t *s, float vol) } int -sa_stream_get_volume_abs(sa_stream_t *s, float *vol) -{ - float volume; - int err; - audio_info_t audio_info; - - if (s == NULL || s->audio_fd == NULL) { +sa_stream_get_volume_abs(sa_stream_t *s, float *vol) { + if (s == NULL || s->output_fd == -1) { return SA_ERROR_NO_INIT; } + if (s->using_oss) { + int mvol; + if (ioctl(s->output_fd, SNDCTL_DSP_GETPLAYVOL, &mvol) < 0){ + return SA_ERROR_SYSTEM; + } + *vol = ((mvol & 0xFF) + (mvol >> 8)) / 200.0f; + return SA_SUCCESS; + } + + pthread_mutex_lock(&s->mutex); + audio_info_t audio_info; AUDIO_INITINFO(&audio_info); - err=ioctl(s->audio_fd,AUDIO_GETINFO,&audio_info); + int err = ioctl(s->output_fd, AUDIO_GETINFO, &audio_info); + pthread_mutex_unlock(&s->mutex); + if (err == -1) { - perror("sa_stream_get_volume_abs failed"); + perror("sa_stream_get_volume_abs failed\n"); return SA_ERROR_SYSTEM; } - volume = (float)((audio_info.play.gain - AUDIO_MIN_GAIN))/(AUDIO_MAX_GAIN - AUDIO_MIN_GAIN); - - *vol = volume; + *vol = (float)((audio_info.play.gain - AUDIO_MIN_GAIN))/(AUDIO_MAX_GAIN - AUDIO_MIN_GAIN); return SA_SUCCESS; } @@ -487,8 +710,6 @@ sa_stream_get_volume_abs(sa_stream_t *s, float *vol) */ #define UNSUPPORTED(func) func { return SA_ERROR_NOT_SUPPORTED; } -UNSUPPORTED(int sa_stream_pause(sa_stream_t *s)) -UNSUPPORTED(int sa_stream_resume(sa_stream_t *s)) UNSUPPORTED(int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec)) UNSUPPORTED(int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size)) UNSUPPORTED(int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size)) @@ -543,7 +764,6 @@ UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const v UNSUPPORTED(int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence)) UNSUPPORTED(int sa_stream_pwrite_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence)) UNSUPPORTED(int sa_stream_get_read_size(sa_stream_t *s, size_t *size)) -UNSUPPORTED(int sa_stream_drain(sa_stream_t *s)) const char *sa_strerror(int code) { return NULL; }