qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] arts support
@ 2005-01-27  4:01 Jim C. Brown
  2005-01-27 22:28 ` malc
  0 siblings, 1 reply; 3+ messages in thread
From: Jim C. Brown @ 2005-01-27  4:01 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 526 bytes --]

This is a preliminary version of oss.c that uses libartsc to play sound instead
of using OSS. It doesn't work (sb.o driver under Linux 2.2.5 kernel complains
of DMA/IRQ timeouts, and no sounds play) but it's a start.

To use it, just replace oss.c with this file, and edit the Makefile in i386-softmmu
and append the output of `artsc-config --cflags` to CFLAGS and the output of
`artsc-config --libs` to LIBS, and then recompile.

-- 
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.

[-- Attachment #2: arts.c --]
[-- Type: text/plain, Size: 9412 bytes --]

/*
 * QEMU Arts Audio output driver
 * 
 * Copyright (c) 2003 Vassili Karpov (malc)
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include "vl.h"

#if !defined(_WIN32) && !defined(__APPLE__)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/soundcard.h> /* for AUD_FMT_* stuff */
#include <artsc.h>

#define MIN(a, b) ((a)>(b)?(b):(a))
#define MAX(a, b) ((a)<(b)?(b):(a))

int qa_errno = 0; /* qemu artsc errno */

#define DEREF(x) (void)x
#define log(...) fprintf (stderr, "artsc: " __VA_ARGS__)
#define ERRFail(...) do {                                       \
    fprintf (stderr, "artsc: " __VA_ARGS__);                      \
    fprintf (stderr, "arts error: %s\n", arts_error_text(qa_errno));  \
    abort ();                                                   \
} while (0)
#define Fail(...) do {                          \
    fprintf (stderr, "artsc: " __VA_ARGS__);      \
    fprintf (stderr, "\n");                     \
    abort ();                                   \
} while (0)

#ifdef DEBUG_OSS
#define lwarn(...) fprintf (stderr, "artsc: " __VA_ARGS__)
#define linfo(...) fprintf (stderr, "artsc: " __VA_ARGS__)
#define ldebug(...) fprintf (stderr, "artsc: " __VA_ARGS__)
#else
#define lwarn(...)
#define linfo(...)
#define ldebug(...)
#endif


static struct {
    int stream_inited;
    arts_stream_t stream;
    int freq;
    int bits16;
    int nchannels;
    int rpos;
    int wpos;
    int live;
    int oss_fmt;
    int bytes_per_second;
    void *buf;
    int bufsize;
    int nfrags;
    int fragsize;
    int old_optr;
    int leftover;
    uint64_t old_ticks;
} oss = { .stream_inited = 0, .buf = NULL };

static struct {
    int nfrags;
    int fragsize;
} conf = {
    .nfrags = 4,
    .fragsize = 4096
};

static enum {DONT, DSP, TID} est = DONT;

static void do_open ()
{
    oss.stream = arts_play_stream(oss.freq, oss.oss_fmt, oss.nchannels, "qemu-arts");
    oss.stream_inited = 1;

    arts_stream_set(oss.stream, ARTS_P_BLOCKING, 0);

    arts_stream_set(oss.stream, ARTS_P_PACKET_SIZE, conf.fragsize);
    arts_stream_set(oss.stream, ARTS_P_PACKET_COUNT, conf.nfrags);

    oss.nfrags = arts_stream_get(oss.stream, ARTS_P_PACKET_COUNT);
    oss.fragsize = arts_stream_get(oss.stream, ARTS_P_PACKET_SIZE);
    oss.bufsize = arts_stream_get(oss.stream, ARTS_P_BUFFER_SIZE);
    oss.old_optr = 0;

    if (oss.buf != NULL)
    {
	oss.buf = realloc(oss.buf, oss.bufsize);
    }
    else
    {
	oss.buf = malloc(oss.bufsize);
    }

    oss.bytes_per_second = (oss.freq << (oss.nchannels >> 1)) << oss.bits16;

    linfo ("bytes per second %d\n", oss.bytes_per_second);

    linfo ("fragments %d, fragstotal %d, fragsize %d, bytes %d, bufsize %d\n",
	   0, /* what is this? */
	   oss.nfrags,
	   oss.fragsize,
	   0, /* what is this? */
	   oss.bufsize);

    oss.rpos = 0;
    oss.wpos = 0;
    oss.live = 0;

}

static void maybe_open (int req_freq, int req_nchannels,
			audfmt_e req_fmt, int force_open)
{
    int oss_fmt, bits16;

    switch (req_fmt) {
    case AUD_FMT_S8:
    case AUD_FMT_U8:
	bits16 = 0;
	oss_fmt = 8;
	break;

    case AUD_FMT_S16:
    case AUD_FMT_U16:
	bits16 = 1;
	oss_fmt = 16;
	break;

    default:
	abort ();
    }

    if (force_open
	|| (!oss.stream_inited)
	|| (oss_fmt != oss.oss_fmt)
	|| (req_nchannels != oss.nchannels)
	|| (req_freq != oss.freq)
	|| (bits16 != oss.bits16)) {
	oss.oss_fmt = oss_fmt;
	oss.nchannels = req_nchannels;
	oss.freq = req_freq;
	oss.bits16 = bits16;
	do_open ();
    }
}

void AUD_reset (int req_freq, int req_nchannels, audfmt_e req_fmt)
{
    maybe_open (req_freq, req_nchannels, req_fmt, 0);
}

void AUD_open (int req_freq, int req_nchannels, audfmt_e req_fmt)
{
    maybe_open (req_freq, req_nchannels, req_fmt, 1);
}

int AUD_write (void *in_buf, int size)
{
    int to_copy;

    to_copy = MIN (oss.bufsize - oss.live, size);
    memcpy(oss.buf, in_buf, to_copy);
    oss.live += to_copy;

    return to_copy;
}

void AUD_run(void)
{
    int to_copy, temp;

    to_copy = oss.live;

    temp = to_copy;

    while (temp) {
	int copy;

	copy = MIN (temp, oss.bufsize - oss.rpos);
	qa_errno = arts_write(oss.stream, oss.buf + oss.rpos, copy);
	if (qa_errno < 0)
	    ERRFail("write error");
        else
            copy = qa_errno;

	oss.rpos += copy;
	if (oss.rpos == oss.bufsize) {
	    oss.rpos = 0;
	}

	temp -= copy;
	oss.live -= copy;
    }
}

#if 0
void AUD_run (void)
{
    int res;
    int bytes;
    struct audio_buf_info abinfo;

    if (0 == oss.live)
	return;

    if (oss.is_mapped) {
	count_info info;

	res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info);
	if (-1 == res) {
	    int err;

	    err = errno;
	    lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
	    return;
	}

	if (info.ptr > oss.old_optr) {
	    bytes = info.ptr - oss.old_optr;
	}
	else {
	    bytes = oss.bufsize + info.ptr - oss.old_optr;
	}

	oss.old_optr = info.ptr;
	oss.live -= bytes;
	return;
    }

    res = ioctl (oss.fd, SNDCTL_DSP_GETOSPACE, &abinfo);

    if (-1 == res) {
	int err;

	err = errno;
	lwarn ("SNDCTL_DSP_GETOSPACE failed with %s\n", strerror (err));
    }

    bytes = abinfo.bytes;
    bytes = MIN (oss.live, bytes);
#if 0
    bytes = (bytes / fragsize) * fragsize;
#endif

    while (bytes) {
	int left, play, written;

	left = oss.bufsize - oss.rpos;
	play = MIN (left, bytes);
	written = write (oss.fd, (uint8_t *)oss.buf + oss.rpos, play);

	if (-1 == written) {
	    if (EAGAIN == errno || EINTR == errno) {
		return;
	    }
	    else {
		ERRFail ("write audio");
	    }
	}

	play = written;
	oss.live -= play;
	oss.rpos += play;
	bytes -= play;

	if (oss.rpos == oss.bufsize) {
	    oss.rpos = 0;
	}
    }
}
#endif

#if 0
static int get_dsp_bytes (void)
{
    int res;
    struct count_info info;

    res = ioctl (oss.fd, SNDCTL_DSP_GETOPTR, &info);
    if (-1 == res) {
	int err;

	err = errno;
	lwarn ("SNDCTL_DSP_GETOPTR failed with %s\n", strerror (err));
	return -1;
    }
    else {
	ldebug ("bytes %d\n", info.bytes);
	return info.bytes;
    }
}
#endif

void AUD_adjust_estimate (int leftover)
{
    oss.leftover = leftover;
}

int AUD_get_free (void)
{
    int free, elapsed;

    free = oss.bufsize - oss.live;

    if (0 == free)
	return 0;

    elapsed = free;
/* not sure how to implement this via arts */
#if 0
    switch (est) {
    case DONT:
	break;

    case DSP:
	{
	    static int old_bytes;
	    int bytes;

	    bytes = get_dsp_bytes ();
	    if (bytes <= 0)
		return free;

	    elapsed = bytes - old_bytes;
	    old_bytes = bytes;
	    ldebug ("dsp elapsed %d bytes\n", elapsed);
	    break;
	}

    case TID:
	{
	    uint64_t ticks, delta;
	    uint64_t ua_elapsed;
	    uint64_t al_elapsed;

	    ticks = qemu_get_clock(rt_clock);
	    delta = ticks - oss.old_ticks;
	    oss.old_ticks = ticks;

	    ua_elapsed = (delta * oss.bytes_per_second) / 1000;
	    al_elapsed = ua_elapsed & ~3ULL;

	    ldebug ("tid elapsed %llu bytes\n", ua_elapsed);

	    if (al_elapsed > (uint64_t) INT_MAX)
		elapsed = INT_MAX;
	    else
		elapsed = al_elapsed;

	    elapsed += oss.leftover;
	}
    }
#endif

    if (elapsed > free) {
	lwarn ("audio can not keep up elapsed %d free %d\n", elapsed, free);
	return free;
    }
    else {
	return elapsed;
    }
}

int AUD_get_live (void)
{
    return oss.live;
}

int AUD_get_buffer_size (void)
{
    return oss.bufsize;
}

#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"

static int get_conf_val (const char *key, int defval)
{
    int val = defval;
    char *strval;

    strval = getenv (key);
    if (strval) {
	val = atoi (strval);
    }

    return val;
}

void AUD_init (void)
{
    qa_errno = arts_init();
    if (qa_errno < 0)
	ERRFail("failed to initialize arts");

    conf.fragsize = get_conf_val (QC_OSS_FRAGSIZE, conf.fragsize);
    conf.nfrags = get_conf_val (QC_OSS_NFRAGS, conf.nfrags);

}

void AUD_cleanup(void)
{
    arts_close_stream(oss.stream);
    oss.stream_inited = 0;
    arts_free();
}

#else

void AUD_run (void)
{
}

int AUD_write (void *in_buf, int size)
{
    return 0;
}

void AUD_reset (int rfreq, int rnchannels, audfmt_e rfmt)
{
}

void AUD_adjust_estimate (int _leftover)
{
}

int AUD_get_free (void)
{
    return 0;
}

int AUD_get_live (void)
{
    return 0;
}

int AUD_get_buffer_size (void)
{
    return 0;
}

void AUD_init (void)
{
}

#endif

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] arts support
  2005-01-27  4:01 [Qemu-devel] arts support Jim C. Brown
@ 2005-01-27 22:28 ` malc
  2005-01-28  4:35   ` Jim C. Brown
  0 siblings, 1 reply; 3+ messages in thread
From: malc @ 2005-01-27 22:28 UTC (permalink / raw)
  To: qemu-devel

On Wed, 26 Jan 2005, Jim C. Brown wrote:

> This is a preliminary version of oss.c that uses libartsc to play sound instead
> of using OSS. It doesn't work (sb.o driver under Linux 2.2.5 kernel complains
> of DMA/IRQ timeouts, and no sounds play) but it's a start.

For one thing there is no oss.c in QEMU for a long time now,
if you want arts support - code apropriate driver along the
lines of the stuff present in audio/*

-- 
mailto:malc@pulsesoft.com

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Qemu-devel] arts support
  2005-01-27 22:28 ` malc
@ 2005-01-28  4:35   ` Jim C. Brown
  0 siblings, 0 replies; 3+ messages in thread
From: Jim C. Brown @ 2005-01-28  4:35 UTC (permalink / raw)
  To: qemu-devel

On Fri, Jan 28, 2005 at 01:28:13AM +0300, malc wrote:
> On Wed, 26 Jan 2005, Jim C. Brown wrote:
> 
> >This is a preliminary version of oss.c that uses libartsc to play sound 
> >instead
> >of using OSS. It doesn't work (sb.o driver under Linux 2.2.5 kernel 
> >complains
> >of DMA/IRQ timeouts, and no sounds play) but it's a start.

And I wrote it because using artsdsp on top of the oss audio driver didn't work
-- somehow the oss driver bypassed it.

> 
> For one thing there is no oss.c in QEMU for a long time now,
> if you want arts support - code apropriate driver along the
> lines of the stuff present in audio/*

Turns out I didn't have to go to all this trouble. After updating my sources,
I found that artsdsp works fine with the SDL audio driver. Not the same as
native arts support, but I can live with it.

> 
> -- 
> mailto:malc@pulsesoft.com
> 
> 
> _______________________________________________
> Qemu-devel mailing list
> Qemu-devel@nongnu.org
> http://lists.nongnu.org/mailman/listinfo/qemu-devel
> 

-- 
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2005-01-28  4:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-27  4:01 [Qemu-devel] arts support Jim C. Brown
2005-01-27 22:28 ` malc
2005-01-28  4:35   ` Jim C. Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).