summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2001-10-14 14:39:36 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2001-10-14 14:39:36 +0000
commit8dc01b84663c7e241778c31a29f0b03c5a8ff784 (patch)
tree5b18dfeb765f3ae799731d6bf8cef0549003e4d6 /src
parent4bdfb0f58e467d91e7f7f0b36dd697373bb595d1 (diff)
downloadxine-lib-8dc01b84663c7e241778c31a29f0b03c5a8ff784.tar.gz
xine-lib-8dc01b84663c7e241778c31a29f0b03c5a8ff784.tar.bz2
system clock based softsync, based on work by Bill Fink <billfink@mindspring.com>
CVS patchset: 798 CVS date: 2001/10/14 14:39:36
Diffstat (limited to 'src')
-rw-r--r--src/audio_out/audio_oss_out.c227
-rw-r--r--src/xine-engine/audio_out.c88
2 files changed, 175 insertions, 140 deletions
diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c
index c3890c5a2..2ad509a23 100644
--- a/src/audio_out/audio_oss_out.c
+++ b/src/audio_out/audio_oss_out.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_oss_out.c,v 1.42 2001/10/07 22:44:57 guenter Exp $
+ * $Id: audio_oss_out.c,v 1.43 2001/10/14 14:39:36 guenter Exp $
*
* 20-8-2001 First implementation of Audio sync and Audio driver separation.
* Copyright (C) 2001 James Courtier-Dutton James@superbug.demon.co.uk
@@ -64,6 +64,8 @@
#include "audio_out.h"
#include "utils.h"
+#include <sys/time.h>
+
#ifndef AFMT_S16_NE
# if defined(sparc) || defined(__sparc__) || defined(PPC)
/* Big endian machines */
@@ -86,9 +88,12 @@
#define ZERO_BUF_SIZE 15360
#define GAP_TOLERANCE 5000
-#define GAP_NONRT_TOLERANCE 15000
#define MAX_GAP 90000
-#define NOT_REAL_TIME -1
+
+#define OSS_SYNC_AUTO_DETECT 0
+#define OSS_SYNC_GETODELAY 1
+#define OSS_SYNC_GETOPTR 2
+#define OSS_SYNC_SOFTSYNC 3
#ifdef CONFIG_DEVFS_FS
#define DSP_TEMPLATE "/dev/sound/dsp%d"
@@ -96,9 +101,6 @@
#define DSP_TEMPLATE "/dev/dsp%d"
#endif
-static int checked_getoptr = 0;
-static int use_getodelay = 0;
-
typedef struct oss_driver_s {
ao_driver_t ao_driver;
@@ -110,14 +112,14 @@ typedef struct oss_driver_s {
config_values_t *config;
int32_t output_sample_rate, input_sample_rate;
+ int32_t output_sample_k_rate;
uint32_t num_channels;
uint32_t bits_per_sample;
uint32_t bytes_per_frame;
uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */
int audio_started;
- int audio_has_realtime; /* OSS driver supports real-time */
-
+ int sync_method;
struct {
char *name;
@@ -126,14 +128,15 @@ typedef struct oss_driver_s {
int mute;
} mixer;
+ struct timeval start_time;
} oss_driver_t;
/*
* open the audio device for writing to
*/
static int ao_oss_open(ao_driver_t *this_gen,
- uint32_t bits, uint32_t rate, int mode)
-{
+ uint32_t bits, uint32_t rate, int mode) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
int tmp;
@@ -200,6 +203,7 @@ static int ao_oss_open(ao_driver_t *this_gen,
}
}
this->output_sample_rate = tmp;
+ this->output_sample_k_rate = this->output_sample_rate / 1000;
xprintf (VERBOSE|AUDIO, "audio_oss_out: audio rate : %d requested, %d provided by device/sec\n",
this->input_sample_rate, this->output_sample_rate);
}
@@ -242,6 +246,7 @@ static int ao_oss_open(ao_driver_t *this_gen,
}
this->num_channels = 2; /* FIXME: is this correct ? */
this->output_sample_rate = this->input_sample_rate;
+ this->output_sample_k_rate = this->output_sample_rate / 1000;
printf ("audio_oss_out : AO_CAP_MODE_A52\n");
break;
}
@@ -269,82 +274,72 @@ static int ao_oss_open(ao_driver_t *this_gen,
ioctl(this->audio_fd,SNDCTL_DSP_SETFRAGMENT,&tmp);
*/
- /*
- * Final check of realtime capability, make sure GETOPTR
- * doesn't return an error.
- */
- if ( this->audio_has_realtime && !checked_getoptr ) {
- count_info info;
- int ret = ioctl(this->audio_fd, SNDCTL_DSP_GETOPTR, &info);
- if ( ret == -1 && errno == EINVAL ) {
- this->audio_has_realtime = 0;
- printf("audio_oss_out: Audio driver SNDCTL_DSP_GETOPTR reports %s,"
- " disabling realtime sync...\n", strerror(errno) );
- printf("audio_oss_out: ...Will use video master clock for soft-sync instead\n");
- printf("audio_oss_out: ...There may be audio/video synchronization issues\n");
- }
- checked_getoptr = 1;
- }
-
- /*
- * check if SNDCTL_DSP_GETODELAY works. if so, using it is preferred.
- */
- if ( this->audio_has_realtime && checked_getoptr ) {
- count_info info;
- int ret = ioctl(this->audio_fd, SNDCTL_DSP_GETODELAY, &info);
- if ( ret != -1 && errno != EINVAL ) {
- printf("audio_oss_out: using SNDCTL_DSP_GETODELAY\n");
- use_getodelay = 1;
- }
- }
-
+ if (this->sync_method == OSS_SYNC_SOFTSYNC)
+ gettimeofday(&this->start_time, NULL);
return this->output_sample_rate;
}
-static int ao_oss_num_channels(ao_driver_t *this_gen)
-{
+static int ao_oss_num_channels(ao_driver_t *this_gen) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
return this->num_channels;
}
-static int ao_oss_bytes_per_frame(ao_driver_t *this_gen)
-{
+static int ao_oss_bytes_per_frame(ao_driver_t *this_gen) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
+
return this->bytes_per_frame;
}
-static int ao_oss_get_gap_tolerance (ao_driver_t *this_gen)
-{
- oss_driver_t *this = (oss_driver_t *) this_gen;
- if (this->audio_has_realtime)
- return GAP_TOLERANCE;
- else
- return GAP_NONRT_TOLERANCE;
+static int ao_oss_get_gap_tolerance (ao_driver_t *this_gen){
+
+ /* oss_driver_t *this = (oss_driver_t *) this_gen; */
+
+ return GAP_TOLERANCE;
}
-static int ao_oss_delay(ao_driver_t *this_gen)
-{
+static int ao_oss_delay(ao_driver_t *this_gen) {
+
count_info info;
oss_driver_t *this = (oss_driver_t *) this_gen;
int bytes_left;
+ int frames;
+ struct timeval tv;
- if (this->audio_has_realtime) {
- if (use_getodelay) {
- ioctl (this->audio_fd, SNDCTL_DSP_GETODELAY, &bytes_left);
- } else {
- ioctl (this->audio_fd, SNDCTL_DSP_GETOPTR, &info);
-
- bytes_left = this->bytes_in_buffer - info.bytes; /* calc delay */
-
- if (bytes_left<=0) /* buffer ran dry */
- bytes_left = 0;
- }
+ switch (this->sync_method) {
- } else {
- return NOT_REAL_TIME;
- }
+ case OSS_SYNC_SOFTSYNC:
+ /* use system real-time clock to get pseudo audio frame position */
+
+ gettimeofday(&tv, NULL);
+
+ frames = (tv.tv_usec + 1000000 - this->start_time.tv_usec)
+ * this->output_sample_k_rate / 1000;
+ frames += (tv.tv_sec - this->start_time.tv_sec)
+ * this->output_sample_rate;
+ frames -= this->output_sample_rate;
+
+ /* calc delay */
+
+ bytes_left = this->bytes_in_buffer - frames * this->bytes_per_frame;
+ if (bytes_left<=0) /* buffer ran dry */
+ bytes_left = 0;
+ break;
+ case OSS_SYNC_GETOPTR:
+ ioctl (this->audio_fd, SNDCTL_DSP_GETOPTR, &info);
+
+ bytes_left = this->bytes_in_buffer - info.bytes; /* calc delay */
+
+ if (bytes_left<=0) /* buffer ran dry */
+ bytes_left = 0;
+ break;
+ case OSS_SYNC_GETODELAY:
+ ioctl (this->audio_fd, SNDCTL_DSP_GETODELAY, &bytes_left);
+ break;
+ }
return bytes_left / this->bytes_per_frame;
}
@@ -355,30 +350,54 @@ static int ao_oss_delay(ao_driver_t *this_gen)
* I.E. Stereo 16 bits audio frames are 4 bytes.
*/
static int ao_oss_write(ao_driver_t *this_gen,
- int16_t* frame_buffer, uint32_t num_frames)
-{
+ int16_t* frame_buffer, uint32_t num_frames) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
+ if (this->sync_method == OSS_SYNC_SOFTSYNC) {
+ int simulated_bytes_in_buffer, frames ;
+ struct timeval tv;
+ /* check if simulated buffer ran dry */
+
+ gettimeofday(&tv, NULL);
+
+ frames = (tv.tv_usec + 1000000 - this->start_time.tv_usec)
+ * this->output_sample_k_rate / 1000;
+ frames += (tv.tv_sec - this->start_time.tv_sec)
+ * this->output_sample_rate;
+ frames -= this->output_sample_rate;
+
+ /* calc delay */
+
+ simulated_bytes_in_buffer = frames * this->bytes_per_frame;
+
+ if (this->bytes_in_buffer < simulated_bytes_in_buffer)
+ this->bytes_in_buffer = simulated_bytes_in_buffer;
+ }
+
this->bytes_in_buffer += num_frames * this->bytes_per_frame;
return write(this->audio_fd, frame_buffer, num_frames * this->bytes_per_frame);
}
-static void ao_oss_close(ao_driver_t *this_gen)
-{
+static void ao_oss_close(ao_driver_t *this_gen) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
+
close(this->audio_fd);
this->audio_fd = -1;
}
static uint32_t ao_oss_get_capabilities (ao_driver_t *this_gen) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
+
return this->capabilities;
}
-static void ao_oss_exit(ao_driver_t *this_gen)
-{
- oss_driver_t *this = (oss_driver_t *) this_gen;
+static void ao_oss_exit(ao_driver_t *this_gen) {
+
+ oss_driver_t *this = (oss_driver_t *) this_gen;
config_values_t *config = this->config;
config->set_int (config, "mixer_volume", this->mixer.volume);
@@ -391,6 +410,7 @@ static void ao_oss_exit(ao_driver_t *this_gen)
}
static int ao_oss_get_property (ao_driver_t *this_gen, int property) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
int mixer_fd;
int audio_devs;
@@ -433,6 +453,7 @@ static int ao_oss_get_property (ao_driver_t *this_gen, int property) {
}
static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) {
+
oss_driver_t *this = (oss_driver_t *) this_gen;
int mixer_fd;
int audio_devs;
@@ -603,23 +624,44 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) {
status = ioctl(audio_fd, SOUND_PCM_WRITE_RATE, &arg);
/*
- * get capabilities
+ * find out which sync method to use
*/
- ioctl (audio_fd, SNDCTL_DSP_GETCAPS, &caps);
+ this->sync_method = config->lookup_int (config, "oss_audio_sync",
+ OSS_SYNC_AUTO_DETECT);
- if ((caps & DSP_CAP_REALTIME) > 0) {
- xprintf (VERBOSE|AUDIO, "audio_oss_out : realtime check: passed :-)\n");
- this->audio_has_realtime = 1;
- } else {
- printf ("audio_oss_out : realtime check: *FAILED* :-(((((\n");
- this->audio_has_realtime = 0;
+ if (this->sync_method == OSS_SYNC_AUTO_DETECT) {
+
+ ioctl (audio_fd, SNDCTL_DSP_GETCAPS, &caps);
+
+ if ((caps & DSP_CAP_REALTIME) > 0) {
+
+ count_info info;
+
+ /*
+ * check if SNDCTL_DSP_GETODELAY works. if so, using it is preferred.
+ */
+
+ if (ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &info) != -1) {
+ printf("audio_oss_out: using SNDCTL_DSP_GETODELAY\n");
+ this->sync_method = OSS_SYNC_GETODELAY;
+ } else if (ioctl(this->audio_fd, SNDCTL_DSP_GETOPTR, &info) != -1) {
+ printf("audio_oss_out: using SNDCTL_DSP_GETOPTR\n");
+ this->sync_method = OSS_SYNC_GETOPTR;
+ } else
+ this->sync_method = OSS_SYNC_SOFTSYNC;
+ } else {
+ printf ("audio_oss_out: realtime check: *FAILED*\n");
+
+ this->sync_method = OSS_SYNC_SOFTSYNC;
+ }
}
- if( !this->audio_has_realtime ) {
- printf("audio_oss_out: Audio driver realtime sync disabled...\n");
- printf("audio_oss_out: ...Will use video master clock for soft-sync instead\n");
- printf("audio_oss_out: ...There may be audio/video synchronization issues\n");
+ if (this->sync_method == OSS_SYNC_SOFTSYNC) {
+ gettimeofday(&this->start_time, NULL);
+ printf ("audio_oss_out: Audio driver realtime sync disabled...\n");
+ printf ("audio_oss_out: ...will use system real-time clock for soft-sync instead\n");
+ printf ("audio_oss_out: ...there may be audio/video synchronization issues\n");
}
this->capabilities = 0;
@@ -712,16 +754,14 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) {
*/
this->capabilities |= AO_CAP_MUTE_VOL;
- }
- else {
+ } else {
if(strcmp(this->mixer.name, "/dev/mixer")) {
config->set_str(config, "mixer_name", "/dev/mixer");
config->save(config);
goto __again;
- }
- else
- printf("%s(): open() %s failed: %s\n",
- __FUNCTION__, this->mixer.name, strerror(errno));
+ } else
+ printf ("audio_oss_out: open() mixer %s failed: %s\n",
+ this->mixer.name, strerror(errno));
}
this->mixer.mute = 0;
@@ -733,8 +773,9 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) {
}
close (audio_fd);
- this->output_sample_rate = 0;
- this->audio_fd = -1;
+ this->output_sample_rate = 0;
+ this->output_sample_k_rate = 0;
+ this->audio_fd = -1;
this->config = config;
this->ao_driver.get_capabilities = ao_oss_get_capabilities;
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
index a7f5d80f8..e4a4acb56 100644
--- a/src/xine-engine/audio_out.c
+++ b/src/xine-engine/audio_out.c
@@ -17,7 +17,7 @@
* along with self program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_out.c,v 1.20 2001/10/07 22:44:57 guenter Exp $
+ * $Id: audio_out.c,v 1.21 2001/10/14 14:39:36 guenter Exp $
*
* 22-8-2001 James imported some useful AC3 sections from the previous alsa driver.
* (c) 2001 Andy Lo A Foe <andy@alsaplayer.org>
@@ -262,58 +262,52 @@ static int ao_write(ao_instance_t *this,
else
delay = 0;
- if ((delay >=0) /* audio driver supports realtime */
- || !this->audio_started) {
-
- /*
- * where, in the timeline is the "end" of the audio buffer at the moment?
- */
-
- cur_time = this->metronom->get_current_time (this->metronom);
- buffer_vpts = cur_time;
-
- /* External A52 decoder delay correction */
- if ((this->mode==AO_CAP_MODE_A52) || (this->mode==AO_CAP_MODE_AC5))
- delay+=10;
+ /*
+ * where, in the timeline is the "end" of the audio buffer at the moment?
+ */
- buffer_vpts += delay * 1024 / this->frames_per_kpts;
+ cur_time = this->metronom->get_current_time (this->metronom);
+ buffer_vpts = cur_time;
+
+ /* External A52 decoder delay correction */
+ if ((this->mode==AO_CAP_MODE_A52) || (this->mode==AO_CAP_MODE_AC5))
+ delay+=10;
+
+ buffer_vpts += delay * 1024 / this->frames_per_kpts;
+
+ /*
+ * calculate gap:
+ */
+
+ gap = vpts - buffer_vpts;
+
+ /*
+ printf ("vpts : %d buffer_vpts : %d gap %d\n",
+ vpts, buffer_vpts, gap);
+ */
+
+ if (gap>this->gap_tolerance) {
- /*
- * calculate gap:
- */
- gap = vpts - buffer_vpts;
+ if (gap>15000)
+ ao_fill_gap (this, gap);
+ else {
+ printf ("audio_out: adjusting master clock %d -> %d\n",
+ cur_time, cur_time + gap);
+ this->metronom->adjust_clock (this->metronom,
+ cur_time + gap);
+ }
- /*
- printf ("vpts : %d buffer_vpts : %d gap %d\n",
- vpts, buffer_vpts, gap);
- */
+ /* keep xine responsive */
- if (gap>this->gap_tolerance) {
-
-
- if (gap>15000)
- ao_fill_gap (this, gap);
- else {
- printf ("audio_out: adjusting master clock %d -> %d\n",
- cur_time, cur_time + gap);
- this->metronom->adjust_clock (this->metronom,
- cur_time + gap);
- }
-
- /* keep xine responsive */
-
- if (gap>MAX_GAP)
- return 0;
-
- } else if (gap < (-1 * this->gap_tolerance)) {
- bDropPackage = 1;
- xprintf (VERBOSE|AUDIO, "audio_out: audio package (vpts = %d %d)"
- "dropped\n", vpts, gap);
- }
+ if (gap>MAX_GAP)
+ return 0;
- } /* audio driver supports realtime */
-
+ } else if (gap < (-1 * this->gap_tolerance)) {
+ bDropPackage = 1;
+ xprintf (VERBOSE|AUDIO, "audio_out: audio package (vpts = %d %d)"
+ "dropped\n", vpts, gap);
+ }
/*
* resample and output frames