audio.c revision b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync/*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * QEMU Audio subsystem
77b1a2d8b5dbe2c0b5200794914239fee3c8ee5dvboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Copyright (c) 2003-2005 Vassili Karpov (malc)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync *
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Permission is hereby granted, free of charge, to any person obtaining a copy
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync * of this software and associated documentation files (the "Software"), to deal
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * in the Software without restriction, including without limitation the rights
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * copies of the Software, and to permit persons to whom the Software is
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * furnished to do so, subject to the following conditions:
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The above copyright notice and this permission notice shall be included in
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * all copies or substantial portions of the Software.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * THE SOFTWARE.
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#define LOG_GROUP LOG_GROUP_DEV_AUDIO
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/pdm.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <VBox/err.h>
662d52947eeb3fc8fca3b23991a5eee47077f896vboxsync#include <VBox/mm.h>
da957c069c2a3c582fe265ff88170ce4c42b499dvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync#include <VBox/log.h>
16a9adc14900ca18e6909679a579f6833425e030vboxsync#include <iprt/assert.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <iprt/uuid.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <iprt/string.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include <iprt/alloc.h>
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#include "Builtins.h"
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#include "../../vl_vbox.h"
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#include <ctype.h>
efff36b306e370346025647a158689021df2e1d1vboxsync#include <stdlib.h>
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync#define AUDIO_CAP "audio"
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#include "audio.h"
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#include "audio_int.h"
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync#ifdef RT_OS_WINDOWS
efff36b306e370346025647a158689021df2e1d1vboxsync#define strcasecmp stricmp
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/* #define DEBUG_PLIVE */
efff36b306e370346025647a158689021df2e1d1vboxsync/* #define DEBUG_LIVE */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/* #define DEBUG_OUT */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/* #define DEBUG_CAPTURE */
efff36b306e370346025647a158689021df2e1d1vboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsynctypedef struct DRVAUDIO
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /** The audio interface. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PDMIAUDIOCONNECTOR IAudioConnector;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync /** Pointer to the driver instance. */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync PPDMDRVINS pDrvIns;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync} DRVAUDIO, *PDRVAUDIO;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic struct audio_driver *drvtab[] = {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef RT_OS_LINUX
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync &oss_audio_driver,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef VBOX_WITH_ALSA
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync &alsa_audio_driver,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif
0abd77741a608f6c41c8dfcd4781b8b84adf1044vboxsync#ifdef VBOX_WITH_PULSE
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync &pulse_audio_driver,
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifdef RT_OS_DARWIN
9496f2d398b49813176939d7a339ae513d5175efvboxsync &coreaudio_audio_driver,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#endif
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#ifdef RT_OS_WINDOWS
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync &dsound_audio_driver,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#endif
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#ifdef RT_OS_L4
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync &oss_audio_driver,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#endif
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#ifdef RT_OS_SOLARIS
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync &solaudio_audio_driver,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#endif
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync &no_audio_driver
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync};
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncstatic char *audio_streamname;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncconst char *audio_get_stream_name(void)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return audio_streamname;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstruct fixed_settings {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int enabled;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int nb_voices;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int greedy;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync audsettings_t settings;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync};
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic struct {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync struct fixed_settings fixed_out;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync struct fixed_settings fixed_in;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync union {
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync int hz;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync int64_t ticks;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync } period;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int plive;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync} conf = {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync { /* DAC fixed settings */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync 1, /* enabled */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync 1, /* nb_voices */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync 1, /* greedy */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync {
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync 44100, /* freq */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync 2, /* nchannels */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync AUD_FMT_S16 /* fmt */
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync },
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync { /* ADC fixed settings */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync 1, /* enabled */
9496f2d398b49813176939d7a339ae513d5175efvboxsync 1, /* nb_voices */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync 1, /* greedy */
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync 44100, /* freq */
9496f2d398b49813176939d7a339ae513d5175efvboxsync 2, /* nchannels */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AUD_FMT_S16 /* fmt */
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
21029597fc4b76d0db0c9542daee201447281781vboxsync },
21029597fc4b76d0db0c9542daee201447281781vboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync { 100 }, /* period */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync 0, /* plive */
9496f2d398b49813176939d7a339ae513d5175efvboxsync};
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic AudioState glob_audio_state;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncvolume_t nominal_volume = {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync 0,
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#ifdef FLOAT_MIXENG
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync 1.0,
9496f2d398b49813176939d7a339ae513d5175efvboxsync 1.0
9496f2d398b49813176939d7a339ae513d5175efvboxsync#else
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifndef VBOX
9496f2d398b49813176939d7a339ae513d5175efvboxsync UINT_MAX,
16a9adc14900ca18e6909679a579f6833425e030vboxsync UINT_MAX
16a9adc14900ca18e6909679a579f6833425e030vboxsync#else
16a9adc14900ca18e6909679a579f6833425e030vboxsync INT_MAX,
16a9adc14900ca18e6909679a579f6833425e030vboxsync INT_MAX
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync#endif
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync};
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifdef VBOX
9496f2d398b49813176939d7a339ae513d5175efvboxsyncvolume_t sum_out_volume =
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync 0,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync INT_MAX,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync INT_MAX
16a9adc14900ca18e6909679a579f6833425e030vboxsync};
16a9adc14900ca18e6909679a579f6833425e030vboxsyncvolume_t master_out_volume =
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync 0,
16a9adc14900ca18e6909679a579f6833425e030vboxsync INT_MAX,
16a9adc14900ca18e6909679a579f6833425e030vboxsync INT_MAX
16a9adc14900ca18e6909679a579f6833425e030vboxsync};
16a9adc14900ca18e6909679a579f6833425e030vboxsyncvolume_t pcm_out_volume =
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync 0,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync INT_MAX,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync INT_MAX
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync};
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncvolume_t pcm_in_volume =
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync 0,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync INT_MAX,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync INT_MAX
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync};
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync#endif
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync/* http://www.df.lth.se/~john_e/gems/gem002d.html */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync/* http://www.multi-platforms.com/Tips/PopCount.htm */
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncuint32_t popcount (uint32_t u)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync{
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync u = ((u&0x55555555) + ((u>>1)&0x55555555));
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync u = ((u&0x33333333) + ((u>>2)&0x33333333));
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync u = ( u&0x0000ffff) + (u>>16);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return u;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync}
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncuint32_t lsbindex (uint32_t u)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync{
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return popcount ((u&-u)-1);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync}
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncuint64_t audio_get_clock (void)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync{
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync AudioState *s;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync s = &glob_audio_state;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync return s->pDrvIns->pDrvHlp->pfnTMGetVirtualTime (s->pDrvIns);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync}
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsyncuint64_t audio_get_ticks_per_sec (void)
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync{
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync AudioState *s;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync s = &glob_audio_state;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return s->pDrvIns->pDrvHlp->pfnTMGetVirtualFreq (s->pDrvIns);
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
16a9adc14900ca18e6909679a579f6833425e030vboxsync#error No its not
16a9adc14900ca18e6909679a579f6833425e030vboxsync#else
16a9adc14900ca18e6909679a579f6833425e030vboxsyncint audio_bug (const char *funcname, int cond)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (cond) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync static int shown;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync AUD_log (NULL, "A bug was just triggered in %s\n", funcname);
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!shown) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync shown = 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync AUD_log (NULL, "Save all your work and restart without audio\n");
16a9adc14900ca18e6909679a579f6833425e030vboxsync AUD_log (NULL, "Please send a bug, see www.virtualbox.org\n");
16a9adc14900ca18e6909679a579f6833425e030vboxsync AUD_log (NULL, "I am sorry\n");
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync AUD_log (NULL, "Context:\n");
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync#if defined AUDIO_BREAKPOINT_ON_BUG
16a9adc14900ca18e6909679a579f6833425e030vboxsync# if defined HOST_I386
16a9adc14900ca18e6909679a579f6833425e030vboxsync# if defined __GNUC__
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync __asm__ ("int3");
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync# elif defined _MSC_VER
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync _asm _emit 0xcc;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync# else
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync abort ();
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync# endif
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync# else
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync abort ();
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync# endif
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#endif
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return cond;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#endif
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncstatic inline int audio_bits_to_index (int bits)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync switch (bits) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync case 8:
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync case 16:
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return 1;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync case 32:
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return 2;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync default:
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync audio_bug ("bits_to_index", 1);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync AUD_log (NULL, "invalid bits %d\n", bits);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncvoid *audio_calloc (const char *funcname, int nmemb, size_t size)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int cond;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync size_t len;
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync len = nmemb * size;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync cond = !nmemb || !size;
a9d49c8f2b28a72e6a4db86eee91e4569290157bvboxsync cond |= nmemb < 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync cond |= len < size;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (audio_bug ("audio_calloc", cond)) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
9496f2d398b49813176939d7a339ae513d5175efvboxsync funcname);
9496f2d398b49813176939d7a339ae513d5175efvboxsync AUD_log (NULL, "nmemb=%d size=%" FMTZ "u (len=%" FMTZ "u)\n",
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync nmemb, size, len);
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync return NULL;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return qemu_mallocz (len);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic const char *audio_audfmt_to_string (audfmt_e fmt)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync switch (fmt) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync case AUD_FMT_U8:
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return "U8";
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync case AUD_FMT_U16:
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync return "U16";
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync case AUD_FMT_U32:
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync return "U32";
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync case AUD_FMT_S8:
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync return "S8";
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync case AUD_FMT_S16:
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync return "S16";
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync case AUD_FMT_S32:
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync return "S32";
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync }
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync dolog ("Bogus audfmt %d returning S16\n", fmt);
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync return "S16";
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync}
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsyncstatic audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval,
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync int *defaultp)
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync{
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync if (!strcasecmp (s, "u8")) {
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync *defaultp = 0;
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync return AUD_FMT_U8;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync else if (!strcasecmp (s, "u16")) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync *defaultp = 0;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync return AUD_FMT_U16;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync }
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync else if (!strcasecmp (s, "u32")) {
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync *defaultp = 0;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync return AUD_FMT_U32;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync else if (!strcasecmp (s, "s8")) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *defaultp = 0;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return AUD_FMT_S8;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync else if (!strcasecmp (s, "s16")) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *defaultp = 0;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return AUD_FMT_S16;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync else if (!strcasecmp (s, "s32")) {
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync *defaultp = 0;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync return AUD_FMT_S32;
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync }
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync else {
bbede9c189def47a9880f0ffb03c0c230c774185vboxsync dolog ("Bogus audio format `%s' using %s\n",
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync s, audio_audfmt_to_string (defval));
ffbe6daf773e38167f3cabaf1f063d84ecd063e9vboxsync *defaultp = 1;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return defval;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic audfmt_e audio_get_conf_fmt (const char *envname,
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync audfmt_e defval,
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int *defaultp)
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync const char *var = getenv (envname);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!var) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *defaultp = 1;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return defval;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return audio_string_to_audfmt (var, defval, defaultp);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic int audio_get_conf_int (const char *key, int defval, int *defaultp)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int val;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync char *strval;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync strval = getenv (key);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (strval) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *defaultp = 0;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync val = atoi (strval);
9496f2d398b49813176939d7a339ae513d5175efvboxsync return val;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync else {
9496f2d398b49813176939d7a339ae513d5175efvboxsync *defaultp = 1;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return defval;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsyncstatic const char *audio_get_conf_str (const char *key,
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync const char *defval,
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync int *defaultp)
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync const char *val = getenv (key);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (!val) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *defaultp = 1;
9496f2d398b49813176939d7a339ae513d5175efvboxsync return defval;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync else {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *defaultp = 0;
9496f2d398b49813176939d7a339ae513d5175efvboxsync return val;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncvoid AUD_vlog (const char *cap, const char *fmt, va_list va)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync va_list va2;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync va_copy (va2, va); /* Have to make a copy here or GCC will break. */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (cap) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync Log (("%s: %N", cap, fmt, &va2));
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync else {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync Log (("%N", fmt, &va2));
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync va_end (va2);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync}
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsyncvoid AUD_log (const char *cap, const char *fmt, ...)
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync{
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync va_list va;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync va_start (va, fmt);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync AUD_vlog (cap, fmt, va);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync va_end (va);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsyncstatic void audio_process_options (const char *prefix,
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync struct audio_option *opt)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
9496f2d398b49813176939d7a339ae513d5175efvboxsync char *optname;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync const char vbox_prefix[] = "VBOX_";
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync size_t preflen;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (audio_bug (AUDIO_FUNC, !prefix)) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync dolog ("prefix = NULL\n");
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (audio_bug (AUDIO_FUNC, !opt)) {
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync dolog ("opt = NULL\n");
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync return;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync preflen = strlen (prefix);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync for (; opt->name; opt++) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync size_t len, i;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync int def;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync if (!opt->valp) {
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync dolog ("Option value pointer for `%s' is not set\n",
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync opt->name);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync continue;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync }
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync len = strlen (opt->name);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* len of opt->name + len of prefix + size of vbox_prefix
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * (includes trailing zero) + zero + underscore (on behalf of
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync * sizeof) */
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync optname = qemu_malloc (len + preflen + sizeof (vbox_prefix) + 1);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (!optname) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync dolog ("Could not allocate memory for option name `%s'\n",
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync opt->name);
9496f2d398b49813176939d7a339ae513d5175efvboxsync continue;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync strcpy (optname, vbox_prefix);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync /* copy while upcasing, including trailing zero */
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync for (i = 0; i <= preflen; ++i) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync optname[i + sizeof (vbox_prefix) - 1] = toupper (prefix[i]);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync strcat (optname, "_");
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync strcat (optname, opt->name);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync def = 1;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync switch (opt->tag) {
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync case AUD_OPT_BOOL:
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync case AUD_OPT_INT:
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync {
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync int *intp = opt->valp;
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync *intp = audio_get_conf_int (optname, *intp, &def);
ce03ea57fdcf3d48523b1de5b894feb75e1b34davboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync break;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync case AUD_OPT_FMT:
9496f2d398b49813176939d7a339ae513d5175efvboxsync {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync audfmt_e *fmtp = opt->valp;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync break;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_OPT_STR:
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync {
9496f2d398b49813176939d7a339ae513d5175efvboxsync const char **strp = opt->valp;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync *strp = audio_get_conf_str (optname, *strp, &def);
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync }
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync break;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync default:
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync dolog ("Bad value tag for option `%s' - %d\n",
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync optname, opt->tag);
9496f2d398b49813176939d7a339ae513d5175efvboxsync break;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync if (!opt->overridenp) {
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync opt->overridenp = &opt->overriden;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync *opt->overridenp = !def;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync qemu_free (optname);
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync}
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsyncstatic void audio_print_settings (audsettings_t *as)
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync{
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync switch (as->fmt) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync case AUD_FMT_S8:
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync AUD_log (NULL, "S8");
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync break;
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync case AUD_FMT_U8:
16a9adc14900ca18e6909679a579f6833425e030vboxsync AUD_log (NULL, "U8");
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync break;
9496f2d398b49813176939d7a339ae513d5175efvboxsync case AUD_FMT_S16:
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync AUD_log (NULL, "S16");
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync break;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync case AUD_FMT_U16:
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync AUD_log (NULL, "U16");
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync break;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync case AUD_FMT_S32:
9496f2d398b49813176939d7a339ae513d5175efvboxsync AUD_log (NULL, "S32");
9496f2d398b49813176939d7a339ae513d5175efvboxsync break;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync case AUD_FMT_U32:
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync AUD_log (NULL, "U32");
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync break;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync default:
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync AUD_log (NULL, "invalid(%d)", as->fmt);
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync break;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync }
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync AUD_log (NULL, " endianness=");
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync switch (as->endianness) {
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync case 0:
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync AUD_log (NULL, "little");
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync break;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync case 1:
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync AUD_log (NULL, "big");
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync break;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync default:
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync AUD_log (NULL, "invalid");
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync break;
369a8817da53dbd5ea6ac360ca0376dba003cde4vboxsync }
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync AUD_log (NULL, "\n");
59d7f5939d42ad9d344fbad8401e00a900db92c5vboxsync}
5341459ca931b65de60b5af2a4cba6836b6b45cavboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsyncstatic int audio_validate_settings (audsettings_t *as)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync int invalid;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync invalid = as->nchannels != 1 && as->nchannels != 2;
16a9adc14900ca18e6909679a579f6833425e030vboxsync invalid |= as->endianness != 0 && as->endianness != 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync switch (as->fmt) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_S8:
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_U8:
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_S16:
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_U16:
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_S32:
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_U32:
16a9adc14900ca18e6909679a579f6833425e030vboxsync break;
16a9adc14900ca18e6909679a579f6833425e030vboxsync default:
16a9adc14900ca18e6909679a579f6833425e030vboxsync invalid = 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync break;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync invalid |= as->freq <= 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return invalid ? -1 : 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsyncstatic int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync int bits = 8, sign = 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync switch (as->fmt) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_S8:
16a9adc14900ca18e6909679a579f6833425e030vboxsync sign = 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync case AUD_FMT_U8:
16a9adc14900ca18e6909679a579f6833425e030vboxsync break;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case AUD_FMT_S16:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync sign = 1;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case AUD_FMT_U16:
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync bits = 16;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync break;
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync case AUD_FMT_S32:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync sign = 1;
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync case AUD_FMT_U32:
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync bits = 32;
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync break;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync }
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync return info->freq == as->freq
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync && info->nchannels == as->nchannels
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync && info->sign == sign
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync && info->bits == bits
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync}
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync
efff36b306e370346025647a158689021df2e1d1vboxsyncvoid audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int bits = 8, sign = 0, shift = 0;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync switch (as->fmt) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case AUD_FMT_S8:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync sign = 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case AUD_FMT_U8:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case AUD_FMT_S16:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync sign = 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case AUD_FMT_U16:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync bits = 16;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync shift = 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case AUD_FMT_S32:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync sign = 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case AUD_FMT_U32:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync bits = 32;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync shift = 2;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->freq = as->freq;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->bits = bits;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->sign = sign;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->nchannels = as->nchannels;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->shift = (as->nchannels == 2) + shift;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->align = (1 << info->shift) - 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->bytes_per_second = info->freq << info->shift;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncvoid audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (!len) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync return;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (info->sign) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync memset (buf, 0x00, len << info->shift);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync else {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync switch (info->bits) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case 8:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync memset (buf, 0x80, len << info->shift);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case 16:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
7b067f3f07310bff46d1d6a4ac94d8b9bb7ccccdvboxsync int i;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync uint16_t *p = buf;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int shift = info->nchannels - 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync short s = INT16_MAX;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (info->swap_endianness) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync s = bswap16 (s);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (i = 0; i < len << shift; i++) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync p[i] = s;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync case 32:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int i;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync uint32_t *p = buf;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int shift = info->nchannels - 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int32_t s = INT32_MAX;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (info->swap_endianness) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync s = bswap32 (s);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (i = 0; i < len << shift; i++) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync p[i] = s;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync default:
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n",
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync info->bits);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync/*
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync * Capture
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync */
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic void noop_conv (st_sample_t *dst, const void *src,
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int samples, volume_t *vol)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync (void) src;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync (void) dst;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync (void) samples;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync (void) vol;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic CaptureVoiceOut *audio_pcm_capture_find_specific (
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync AudioState *s,
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync audsettings_t *as
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync )
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync CaptureVoiceOut *cap;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (audio_pcm_info_eq (&cap->hw.info, as)) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync return cap;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync return NULL;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync struct capture_callback *cb;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#ifdef DEBUG_CAPTURE
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync dolog ("notification %d sent\n", cmd);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#endif
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cb->ops.notify (cb->opaque, cmd);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (cap->hw.enabled != enabled) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync audcnotification_e cmd;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cap->hw.enabled = enabled;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync audio_notify_capture (cap, cmd);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsyncstatic void audio_recalc_and_notify_capture (CaptureVoiceOut *cap)
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync HWVoiceOut *hw = &cap->hw;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync SWVoiceOut *sw;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync int enabled = 0;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (sw->active) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync enabled = 1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync break;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync audio_capture_maybe_changed (cap, enabled);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsyncstatic void audio_detach_capture (HWVoiceOut *hw)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync{
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync SWVoiceCap *sc = hw->cap_head.lh_first;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync while (sc) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync SWVoiceCap *sc1 = sc->entries.le_next;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync SWVoiceOut *sw = &sc->sw;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync CaptureVoiceOut *cap = sc->cap;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync int was_active = sw->active;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (sw->rate) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync st_rate_stop (sw->rate);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->rate = NULL;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync }
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync LIST_REMOVE (sw, entries);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync LIST_REMOVE (sc, entries);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync qemu_free (sc);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (was_active) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync /* We have removed soft voice from the capture:
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync this might have changed the overall status of the capture
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync since this might have been the only active voice */
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync audio_recalc_and_notify_capture (cap);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync }
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sc = sc1;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync }
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync}
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsyncstatic int audio_attach_capture (AudioState *s, HWVoiceOut *hw)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync{
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync CaptureVoiceOut *cap;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync audio_detach_capture (hw);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync SWVoiceCap *sc;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync SWVoiceOut *sw;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync HWVoiceOut *hw_cap = &cap->hw;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (!sc) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync dolog ("Could not allocate soft capture voice (%u bytes)\n",
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sizeof (*sc));
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync return -1;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync }
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sc->cap = cap;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw = &sc->sw;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->hw = hw_cap;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->info = hw->info;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->empty = 1;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->active = hw->enabled;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->conv = noop_conv;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (!sw->rate) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw));
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync qemu_free (sw);
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync return -1;
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync }
efff36b306e370346025647a158689021df2e1d1vboxsync LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync LIST_INSERT_HEAD (&hw->cap_head, sc, entries);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#ifdef DEBUG_CAPTURE
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync asprintf (&sw->name, "for %p %d,%d,%d",
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync hw, sw->info.freq, sw->info.bits, sw->info.nchannels);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync dolog ("Added %s active = %d\n", sw->name, sw->active);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#endif
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (sw->active) {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync audio_capture_maybe_changed (cap, 1);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync/*
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync * Hard voice (capture)
ff88d4153cd65650577e8c2d1a5a3fdfa0404a80vboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
fe813b3594039ba864493438e78ee0e7132bc445vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync SWVoiceIn *sw;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int m = hw->total_samples_captured;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (sw->active) {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync m = audio_MIN (m, sw->total_hw_samples_acquired);
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return m;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
ff88d4153cd65650577e8c2d1a5a3fdfa0404a80vboxsyncint audio_pcm_hw_get_live_in (HWVoiceIn *hw)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
fe813b3594039ba864493438e78ee0e7132bc445vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync dolog ("live=%d hw->samples=%d\n", live, hw->samples);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return live;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * Soft voice (capture)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync */
fe813b3594039ba864493438e78ee0e7132bc445vboxsyncstatic int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync HWVoiceIn *hw = sw->hw;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
16a9adc14900ca18e6909679a579f6833425e030vboxsync int rpos;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync dolog ("live=%d hw->samples=%d\n", live, hw->samples);
16a9adc14900ca18e6909679a579f6833425e030vboxsync return 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync rpos = hw->wpos - live;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (rpos >= 0) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync return rpos;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync else {
16a9adc14900ca18e6909679a579f6833425e030vboxsync return hw->samples + rpos;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsyncint audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync HWVoiceIn *hw = sw->hw;
16a9adc14900ca18e6909679a579f6833425e030vboxsync int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync st_sample_t *src, *dst = sw->buf;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync live = hw->total_samples_captured - sw->total_hw_samples_acquired;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
16a9adc14900ca18e6909679a579f6833425e030vboxsync return 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync samples = size >> sw->info.shift;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!live) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync return 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync swlim = (live * sw->ratio) >> 32;
16a9adc14900ca18e6909679a579f6833425e030vboxsync swlim = audio_MIN (swlim, samples);
16a9adc14900ca18e6909679a579f6833425e030vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync while (swlim) {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync src = hw->conv_buf + rpos;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync isamp = hw->wpos - rpos;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* XXX: <= ? */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (isamp <= 0) {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync isamp = hw->samples - rpos;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (!isamp) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync osamp = swlim;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (audio_bug (AUDIO_FUNC, osamp < 0)) {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync dolog ("osamp=%d\n", osamp);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync swlim -= osamp;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync rpos = (rpos + isamp) % hw->samples;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync dst += osamp;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync ret += osamp;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync total += isamp;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync sw->clip (buf, sw->buf, ret);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync sw->total_hw_samples_acquired += total;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return ret << sw->info.shift;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*
fe813b3594039ba864493438e78ee0e7132bc445vboxsync * Hard voice (playback)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync SWVoiceOut *sw;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync int m = INT_MAX;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync int nb_live = 0;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (sw->active || !sw->empty) {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync m = audio_MIN (m, sw->total_hw_samples_mixed);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync nb_live += 1;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync }
594521f7faf13f7a88f31e6cd76629bd67340229vboxsync }
e04eeee1b306d610b0441cee9bf1c750100254d5vboxsync
fe813b3594039ba864493438e78ee0e7132bc445vboxsync *nb_livep = nb_live;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return m;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsyncint audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync{
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync int smin;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync smin = audio_pcm_hw_find_min_out (hw, nb_live);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!*nb_live) {
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync return 0;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync }
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync else {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync int live = smin;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
fe813b3594039ba864493438e78ee0e7132bc445vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync dolog ("live=%d hw->samples=%d\n", live, hw->samples);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return live;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync }
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync}
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncint audio_pcm_hw_get_live_out (HWVoiceOut *hw)
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync{
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync int nb_live;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync int live;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
594521f7faf13f7a88f31e6cd76629bd67340229vboxsync live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
e04eeee1b306d610b0441cee9bf1c750100254d5vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
fe813b3594039ba864493438e78ee0e7132bc445vboxsync dolog ("live=%d hw->samples=%d\n", live, hw->samples);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return live;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync/*
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync * Soft voice (playback)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsyncint audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
af90f37ee9175da3aed36bda13519a917cc4effbvboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int ret = 0, pos = 0, total = 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (!sw) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync return size;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync hwsamples = sw->hw->samples;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
7a3f491705173bc08122f2c7d26d48a8b4c5ceecvboxsync live = sw->total_hw_samples_mixed;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync dolog ("live=%d hw->samples=%d\n", live, hwsamples);
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync return 0;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync }
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync if (live == hwsamples) {
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync#ifdef DEBUG_OUT
9496f2d398b49813176939d7a339ae513d5175efvboxsync dolog ("%s is full %d\n", sw->name, live);
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync return 0;
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync wpos = (sw->hw->rpos + live) % hwsamples;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync samples = size >> sw->info.shift;
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync
fe813b3594039ba864493438e78ee0e7132bc445vboxsync dead = hwsamples - live;
9496f2d398b49813176939d7a339ae513d5175efvboxsync swlim = ((int64_t) dead << 32) / sw->ratio;
9496f2d398b49813176939d7a339ae513d5175efvboxsync swlim = audio_MIN (swlim, samples);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (swlim) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync#ifndef VBOX
9496f2d398b49813176939d7a339ae513d5175efvboxsync sw->conv (sw->buf, buf, swlim, &sw->vol);
9496f2d398b49813176939d7a339ae513d5175efvboxsync#else
9496f2d398b49813176939d7a339ae513d5175efvboxsync sw->conv (sw->buf, buf, swlim, &sum_out_volume);
9496f2d398b49813176939d7a339ae513d5175efvboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync while (swlim) {
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync dead = hwsamples - live;
fe813b3594039ba864493438e78ee0e7132bc445vboxsync left = hwsamples - wpos;
9496f2d398b49813176939d7a339ae513d5175efvboxsync blck = audio_MIN (dead, left);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (!blck) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync isamp = swlim;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync osamp = blck;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync st_rate_flow_mix (
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync sw->rate,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync sw->buf + pos,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync sw->hw->mix_buf + wpos,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync &isamp,
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync &osamp
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync );
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync ret += isamp;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync swlim -= isamp;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pos += isamp;
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync live += osamp;
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync wpos = (wpos + osamp) % hwsamples;
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync total += osamp;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync sw->total_hw_samples_mixed += total;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync sw->empty = sw->total_hw_samples_mixed == 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#ifdef DEBUG_OUT
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync dolog (
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync "%s: write size %d ret %d total sw %d\n",
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync SW_NAME (sw),
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync size >> sw->info.shift,
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync ret,
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync sw->total_hw_samples_mixed
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync );
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#endif
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return ret << sw->info.shift;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#ifdef DEBUG_AUDIO
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncstatic void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync cap, info->bits, info->sign, info->freq, info->nchannels);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#endif
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#define DAC
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#include "audio_template.h"
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#undef DAC
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync#include "audio_template.h"
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncint AUD_write (SWVoiceOut *sw, void *buf, int size)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int bytes;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!sw) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* XXX: Consider options */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return size;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!sw->hw->enabled) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync bytes = sw->hw->pcm_ops->write (sw, buf, size);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return bytes;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncint AUD_read (SWVoiceIn *sw, void *buf, int size)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int bytes;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!sw) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync /* XXX: Consider options */
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return size;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!sw->hw->enabled) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync bytes = sw->hw->pcm_ops->read (sw, buf, size);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return bytes;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncint AUD_get_buffer_size_out (SWVoiceOut *sw)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return sw->hw->samples << sw->hw->info.shift;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncvoid AUD_set_active_out (SWVoiceOut *sw, int on)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync HWVoiceOut *hw;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!sw) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw = sw->hw;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (sw->active != on) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync SWVoiceOut *temp_sw;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync SWVoiceCap *sc;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (on) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw->pending_disable = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!hw->enabled) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw->enabled = 1;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync else {
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (hw->enabled) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync int nb_active = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync for (temp_sw = hw->sw_head.lh_first; temp_sw;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync temp_sw = temp_sw->entries.le_next) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync nb_active += temp_sw->active != 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw->pending_disable = nb_active == 1;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync sc->sw.active = hw->enabled;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (hw->enabled) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync audio_capture_maybe_changed (sc->cap, 1);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync sw->active = on;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync}
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncvoid AUD_set_active_in (SWVoiceIn *sw, int on)
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync{
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync HWVoiceIn *hw;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (!sw) {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync return;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync hw = sw->hw;
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (sw->active != on) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync SWVoiceIn *temp_sw;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (on) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!hw->enabled) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync hw->enabled = 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync sw->total_hw_samples_acquired = hw->total_samples_captured;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync else {
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (hw->enabled) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync int nb_active = 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync for (temp_sw = hw->sw_head.lh_first; temp_sw;
16a9adc14900ca18e6909679a579f6833425e030vboxsync temp_sw = temp_sw->entries.le_next) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync nb_active += temp_sw->active != 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (nb_active == 1) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw->enabled = 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync sw->active = on;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic int audio_get_avail (SWVoiceIn *sw)
cba6719bd64ec749967bbe931230452664109857vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int live;
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync if (!sw) {
cba6719bd64ec749967bbe931230452664109857vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync return 0;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync ldebug (
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "%s: get_avail live %d ret %lld\n",
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync SW_NAME (sw),
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync );
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
090d729e786b999dc285f8ea267f9effd1319544vboxsyncstatic int audio_get_free (SWVoiceOut *sw)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync int live, dead;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!sw) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync return 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync live = sw->total_hw_samples_mixed;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return 0;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync dead = sw->hw->samples - live;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync#ifdef DEBUG_OUT
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync dolog ("%s: get_free live %d dead %d ret %lld\n",
9496f2d398b49813176939d7a339ae513d5175efvboxsync SW_NAME (sw),
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync#endif
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync}
68a4ee3a31a0807abd03eae881c1bbaf4d42ee6dvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsyncstatic void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples)
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync int n;
caf54c14752060b187e3fca12a6f71f4b13126b8vboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (hw->enabled) {
68a4ee3a31a0807abd03eae881c1bbaf4d42ee6dvboxsync SWVoiceCap *sc;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
9496f2d398b49813176939d7a339ae513d5175efvboxsync SWVoiceOut *sw = &sc->sw;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync int rpos2 = rpos;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync n = samples;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync while (n) {
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync int till_end_of_hw = hw->samples - rpos2;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync int to_write = audio_MIN (till_end_of_hw, n);
975ad9d9bc9c4dc96b41d9f67a65228b1b338e2avboxsync int bytes = to_write << hw->info.shift;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync int written;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync sw->buf = hw->mix_buf + rpos2;
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsync written = audio_pcm_sw_write (sw, NULL, bytes);
9496f2d398b49813176939d7a339ae513d5175efvboxsync if (written - bytes) {
da3503c04ce76e653401396fe2795a9bc2427a1dvboxsync dolog ("Could not mix %d bytes into a capture "
9496f2d398b49813176939d7a339ae513d5175efvboxsync "buffer, mixed %d\n",
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync bytes, written);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync break;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync n -= to_write;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync rpos2 = (rpos2 + to_write) % hw->samples;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync }
090d729e786b999dc285f8ea267f9effd1319544vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync n = audio_MIN (samples, hw->samples - rpos);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync mixeng_sniff_and_clear (hw, hw->mix_buf + rpos, n);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync mixeng_sniff_and_clear (hw, hw->mix_buf, samples - n);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic void audio_run_out (AudioState *s)
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync{
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync HWVoiceOut *hw = NULL;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync SWVoiceOut *sw;
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync int played;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int live, free, nb_live, cleanup_required, prev_rpos;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync if (!nb_live) {
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync live = 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync dolog ("live=%d hw->samples=%d\n", live, hw->samples);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync continue;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (hw->pending_disable && !nb_live) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync SWVoiceCap *sc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync#ifdef DEBUG_OUT
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync dolog ("Disabling voice\n");
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync#endif
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync hw->enabled = 0;
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync hw->pending_disable = 0;
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync sc->sw.active = 0;
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync audio_recalc_and_notify_capture (sc->cap);
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync }
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync continue;
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync }
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync if (!live) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync if (sw->active) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync free = audio_get_free (sw);
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync if (free > 0) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync sw->callback.fn (sw->callback.opaque, free);
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync }
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync }
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync }
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync continue;
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync }
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync prev_rpos = hw->rpos;
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync played = hw->pcm_ops->run_out (hw);
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync hw->rpos, hw->samples, played);
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync hw->rpos = 0;
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync }
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync#ifdef DEBUG_OUT
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync dolog ("played=%d\n", played);
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync#endif
16a9adc14900ca18e6909679a579f6833425e030vboxsync
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync if (played) {
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync hw->ts_helper += played;
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync audio_capture_mix_and_clear (hw, prev_rpos, played);
81c82bebae20d8743f59b8f3c38f0b1b7310abb3vboxsync }
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync cleanup_required = 0;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync if (!sw->active && sw->empty) {
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync continue;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
16a9adc14900ca18e6909679a579f6833425e030vboxsync played, sw->total_hw_samples_mixed);
16a9adc14900ca18e6909679a579f6833425e030vboxsync played = sw->total_hw_samples_mixed;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync sw->total_hw_samples_mixed -= played;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!sw->total_hw_samples_mixed) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync sw->empty = 1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync cleanup_required |= !sw->active && !sw->callback.fn;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync if (sw->active) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync free = audio_get_free (sw);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (free > 0) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync sw->callback.fn (sw->callback.opaque, free);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (cleanup_required) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync SWVoiceOut *sw1;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync sw = hw->sw_head.lh_first;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync while (sw) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync sw1 = sw->entries.le_next;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync if (!sw->active && !sw->callback.fn) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#ifdef DEBUG_PLIVE
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync dolog ("Finishing with old voice\n");
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync#endif
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync audio_close_out (s, sw);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync sw = sw1;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync }
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync}
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsyncstatic void audio_run_in (AudioState *s)
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync{
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync HWVoiceIn *hw = NULL;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {
efff36b306e370346025647a158689021df2e1d1vboxsync SWVoiceIn *sw;
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync int captured, min;
efff36b306e370346025647a158689021df2e1d1vboxsync
efff36b306e370346025647a158689021df2e1d1vboxsync captured = hw->pcm_ops->run_in (hw);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync min = audio_pcm_hw_find_min_in (hw);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync hw->total_samples_captured += captured - min;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync hw->ts_helper += captured;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync sw->total_hw_samples_acquired -= min;
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync if (sw->active) {
d571b6e3237f0ce89ea27f6fa4635d41c5ee3d88vboxsync int avail;
efff36b306e370346025647a158689021df2e1d1vboxsync
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync avail = audio_get_avail (sw);
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync if (avail > 0) {
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync sw->callback.fn (sw->callback.opaque, avail);
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync }
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync }
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync }
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync }
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync}
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync
27b178e99b06a68ef52353b15bc647674d2006bcvboxsyncstatic void audio_run_capture (AudioState *s)
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync{
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync CaptureVoiceOut *cap;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) {
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync int live, rpos, captured;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync HWVoiceOut *hw = &cap->hw;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync SWVoiceOut *sw;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync captured = live = audio_pcm_hw_get_live_out (hw);
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync rpos = hw->rpos;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync while (live) {
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync int left = hw->samples - rpos;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync int to_capture = audio_MIN (live, left);
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync st_sample_t *src;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync struct capture_callback *cb;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync src = hw->mix_buf + rpos;
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync hw->clip (cap->buf, src, to_capture);
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync mixeng_sniff_and_clear (hw, src, to_capture);
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync cb->ops.capture (cb->opaque, cap->buf,
27b178e99b06a68ef52353b15bc647674d2006bcvboxsync to_capture << hw->info.shift);
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync rpos = (rpos + to_capture) % hw->samples;
16a9adc14900ca18e6909679a579f6833425e030vboxsync live -= to_capture;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync hw->rpos = rpos;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (!sw->active && sw->empty) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync continue;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
16a9adc14900ca18e6909679a579f6833425e030vboxsync captured, sw->total_hw_samples_mixed);
16a9adc14900ca18e6909679a579f6833425e030vboxsync captured = sw->total_hw_samples_mixed;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync sw->total_hw_samples_mixed -= captured;
16a9adc14900ca18e6909679a579f6833425e030vboxsync sw->empty = sw->total_hw_samples_mixed == 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
bbede9c189def47a9880f0ffb03c0c230c774185vboxsyncstatic void audio_timer (void *opaque)
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync{
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync AudioState *s = opaque;
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync
a3369a746b56a8966dd78619f4d191c9662f400dvboxsync audio_run_out (s);
51fe8789a74f6c118894aaa12eb69ec155386dbdvboxsync audio_run_in (s);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync audio_run_capture (s);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
89929f1c5e76283fd07c1886aa7c861d12df3a67vboxsync TMTimerSet (s->ts, TMTimerGet (s->ts) + conf.period.ticks);
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync}
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsyncstatic struct audio_option audio_options[] = {
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync /* DAC */
c7551981eb6d97331da479f68f14a9c56247e4f7vboxsync {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync "Use fixed settings for host DAC", NULL, 0},
16a9adc14900ca18e6909679a579f6833425e030vboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "Frequency for fixed host DAC", NULL, 0},
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync "Format for fixed host DAC", NULL, 0},
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "Number of voices for DAC", NULL, 0},
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* ADC */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync "Use fixed settings for host ADC", NULL, 0},
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "Frequency for fixed host ADC", NULL, 0},
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "Format for fixed host ADC", NULL, 0},
0ccdfa1953b2f57311fb9ec01a2baf5e1e366f5avboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync "Number of voices for ADC", NULL, 0},
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync /* Misc */
16a9adc14900ca18e6909679a579f6833425e030vboxsync {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
16a9adc14900ca18e6909679a579f6833425e030vboxsync "Timer period in HZ (0 - use lowest possible)", NULL, 0},
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync {"PLIVE", AUD_OPT_BOOL, &conf.plive,
16a9adc14900ca18e6909679a579f6833425e030vboxsync "(undocumented)", NULL, 0},
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync {NULL, 0, NULL, NULL, NULL, 0}
16a9adc14900ca18e6909679a579f6833425e030vboxsync};
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsyncstatic int audio_driver_init (AudioState *s, struct audio_driver *drv)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (drv->options) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync audio_process_options (drv->name, drv->options);
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync s->drv_opaque = drv->init ();
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync if (s->drv_opaque) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync audio_init_nb_voices_out (s, drv);
16a9adc14900ca18e6909679a579f6833425e030vboxsync audio_init_nb_voices_in (s, drv);
16a9adc14900ca18e6909679a579f6833425e030vboxsync s->drv = drv;
16a9adc14900ca18e6909679a579f6833425e030vboxsync return 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync else {
16a9adc14900ca18e6909679a579f6833425e030vboxsync dolog ("Could not init `%s' audio driver\n", drv->name);
16a9adc14900ca18e6909679a579f6833425e030vboxsync return -1;
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsyncstatic void audio_vm_change_state_handler (void *opaque, int running)
16a9adc14900ca18e6909679a579f6833425e030vboxsync{
16a9adc14900ca18e6909679a579f6833425e030vboxsync AudioState *s = opaque;
16a9adc14900ca18e6909679a579f6833425e030vboxsync HWVoiceOut *hwo = NULL;
16a9adc14900ca18e6909679a579f6833425e030vboxsync HWVoiceIn *hwi = NULL;
16a9adc14900ca18e6909679a579f6833425e030vboxsync int op = running ? VOICE_ENABLE : VOICE_DISABLE;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
16a9adc14900ca18e6909679a579f6833425e030vboxsync hwo->pcm_ops->ctl_out (hwo, op);
16a9adc14900ca18e6909679a579f6833425e030vboxsync }
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
670b83d458bceb92123155b5b47a39b9d24e3266vboxsync hwi->pcm_ops->ctl_in (hwi, op);
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync }
670b83d458bceb92123155b5b47a39b9d24e3266vboxsync}
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync
9c149a2789022f5011e88fb62f02a1cc8068e88fvboxsyncstatic void audio_atexit (void)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AudioState *s = &glob_audio_state;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync HWVoiceOut *hwo = NULL;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync HWVoiceIn *hwi = NULL;
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync /* VBox change: audio_pcm_hw_find_any_enabled_out => audio_pcm_hw_find_any_out */
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync while ((hwo = audio_pcm_hw_find_any_out (s, hwo))) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync SWVoiceCap *sc;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync hwo->pcm_ops->fini_out (hwo);
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync CaptureVoiceOut *cap = sc->cap;
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync struct capture_callback *cb;
9496f2d398b49813176939d7a339ae513d5175efvboxsync
9496f2d398b49813176939d7a339ae513d5175efvboxsync for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
5d0d754550d06b7d59a935e59caaf814462d53ccvboxsync cb->ops.destroy (cb->opaque);
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
d80c85a1bc7317da7d0cd1254fae6a20db039c8cvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
9496f2d398b49813176939d7a339ae513d5175efvboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync /* VBox change: audio_pcm_hw_find_any_enabled_in => audio_pcm_hw_find_any_in */
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync while ((hwi = audio_pcm_hw_find_any_in (s, hwi))) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync hwi->pcm_ops->fini_in (hwi);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync }
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync
d1bffa158f98ff3c18f7d085e7372c9ea00e9a43vboxsync if (s->drv) {
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync s->drv->fini (s->drv_opaque);
d1bffa158f98ff3c18f7d085e7372c9ea00e9a43vboxsync }
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync}
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsyncvoid AUD_register_card (const char *name, QEMUSoundCard *card)
f35c44bfc9e1036d0cb376fb144cdae416c7ef3avboxsync{
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync AudioState *s = &glob_audio_state;
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync card->audio = s;
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync card->name = qemu_strdup (name);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync memset (&card->entries, 0, sizeof (card->entries));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LIST_INSERT_HEAD (&s->card_head, card, entries);
927320c7f81d3acdbccb5f3fea7548b4b7184b98vboxsync}
6b223679d40f5e57e55e867e806a9f194e2cde12vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsyncvoid AUD_remove_card (QEMUSoundCard *card)
9496f2d398b49813176939d7a339ae513d5175efvboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LIST_REMOVE (card, entries);
9496f2d398b49813176939d7a339ae513d5175efvboxsync card->audio = NULL;
9496f2d398b49813176939d7a339ae513d5175efvboxsync qemu_free (card->name);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsyncstatic void audio_timer_helper (PPDMDRVINS pDrvIns, PTMTIMER pTimer)
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync AudioState *s = &glob_audio_state;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync audio_timer (s);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync}
16a9adc14900ca18e6909679a579f6833425e030vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsyncstatic int AUD_init (PPDMDRVINS pDrvIns, const char *drvname)
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync{
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync size_t i;
16a9adc14900ca18e6909679a579f6833425e030vboxsync int done = 0;
16a9adc14900ca18e6909679a579f6833425e030vboxsync AudioState *s = &glob_audio_state;
16a9adc14900ca18e6909679a579f6833425e030vboxsync int rc;
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync LIST_INIT (&s->hw_head_out);
16a9adc14900ca18e6909679a579f6833425e030vboxsync LIST_INIT (&s->hw_head_in);
16a9adc14900ca18e6909679a579f6833425e030vboxsync LIST_INIT (&s->cap_head);
16a9adc14900ca18e6909679a579f6833425e030vboxsync
16a9adc14900ca18e6909679a579f6833425e030vboxsync rc = pDrvIns->pDrvHlp->pfnTMTimerCreate (pDrvIns, TMCLOCK_VIRTUAL,
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync audio_timer_helper, "Audio timer", &s->ts);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (RT_FAILURE (rc))
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync return rc;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync audio_process_options ("AUDIO", audio_options);
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync s->nb_hw_voices_out = conf.fixed_out.nb_voices;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync s->nb_hw_voices_in = conf.fixed_in.nb_voices;
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (s->nb_hw_voices_out <= 0) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync dolog ("Bogus number of playback voices %d, setting to 1\n",
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync s->nb_hw_voices_out);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync s->nb_hw_voices_out = 1;
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync }
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync if (s->nb_hw_voices_in <= 0) {
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync dolog ("Bogus number of capture voices %d, setting to 0\n",
4a23807f02e9920d92c8449bd93d84501add460avboxsync s->nb_hw_voices_in);
d9d5fbda1b8f7a6f7fae555db60d0e636fd03af8vboxsync s->nb_hw_voices_in = 0;
4a23807f02e9920d92c8449bd93d84501add460avboxsync }
fe813b3594039ba864493438e78ee0e7132bc445vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogRel(("Audio: Trying driver '%s'.\n", drvname));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (drvname) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync int found = 0;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (!strcmp (drvname, drvtab[i]->name)) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync done = !audio_driver_init (s, drvtab[i]);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync found = 1;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync break;
5b465a7c1237993faf8bb50120d247f3f0319adavboxsync }
09127e6ed46502ff8a6a521713ee8ace53667683vboxsync }
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync if (!found) {
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync dolog ("Unknown audio driver `%s'\n", drvname);
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (!done) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (drvtab[i]->can_be_default) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync LogRel(("Audio: Initialization of driver '%s' failed, trying '%s'.\n",
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync drvname, drvtab[i]->name));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync drvname = drvtab[i]->name;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync done = !audio_driver_init (s, drvtab[i]);
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync if (!done) {
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync done = !audio_driver_init (s, &no_audio_driver);
ad77e3ec3cde24263bc7537575f5cae442bee3b1vboxsync if (!done) {
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync dolog ("Could not initialize audio subsystem\n");
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync else {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync LogRel(("Audio: Initialization of driver '%s' failed, using NULL driver.\n", drvname));
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync dolog ("warning: Using timer based audio emulation\n");
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
8083a259c13e6e26e56ca2582edbad4a8cfac25avboxsync
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync if (done) {
1bf495e3eec00dd79cecb6b36ef2a97f422c3737vboxsync if (conf.period.hz <= 0) {
cba6719bd64ec749967bbe931230452664109857vboxsync if (conf.period.hz < 0) {
cba6719bd64ec749967bbe931230452664109857vboxsync dolog ("warning: Timer period is negative - %d "
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync "treating as zero\n",
9496f2d398b49813176939d7a339ae513d5175efvboxsync conf.period.hz);
9496f2d398b49813176939d7a339ae513d5175efvboxsync }
cba6719bd64ec749967bbe931230452664109857vboxsync conf.period.ticks = 1;
cba6719bd64ec749967bbe931230452664109857vboxsync }
cba6719bd64ec749967bbe931230452664109857vboxsync else {
cba6719bd64ec749967bbe931230452664109857vboxsync conf.period.ticks = pDrvIns->pDrvHlp->pfnTMGetVirtualFreq (pDrvIns)
cba6719bd64ec749967bbe931230452664109857vboxsync / conf.period.hz;
a0240ff4f7663045c848fdbc192ea3d4d9f70a11vboxsync }
cba6719bd64ec749967bbe931230452664109857vboxsync }
else {
/* XXX */
rc = TMTimerDestroy (s->ts);
return rc;
}
LIST_INIT (&s->card_head);
TMTimerSet (s->ts, TMTimerGet (s->ts) + conf.period.ticks);
return VINF_SUCCESS;
}
int AUD_init_null(void)
{
AudioState *s = &glob_audio_state;
#ifdef VBOX
if (s->drv)
s->drv->fini (s->drv_opaque);
#endif
LogRel(("Audio: Using NULL audio driver\n"));
return audio_driver_init (s, &no_audio_driver);
}
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
struct audio_capture_ops *ops,
void *cb_opaque
)
{
CaptureVoiceOut *cap;
struct capture_callback *cb;
if (!s) {
/* XXX suppress */
s = &glob_audio_state;
}
if (audio_validate_settings (as)) {
dolog ("Invalid settings were passed when trying to add capture\n");
audio_print_settings (as);
goto err0;
}
cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
if (!cb) {
dolog ("Could not allocate capture callback information, size %u\n",
sizeof (*cb));
goto err0;
}
cb->ops = *ops;
cb->opaque = cb_opaque;
cap = audio_pcm_capture_find_specific (s, as);
if (cap) {
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
return cap;
}
else {
HWVoiceOut *hw;
CaptureVoiceOut *cap;
cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
if (!cap) {
dolog ("Could not allocate capture voice, size %u\n",
sizeof (*cap));
goto err1;
}
hw = &cap->hw;
LIST_INIT (&hw->sw_head);
LIST_INIT (&cap->cb_head);
/* XXX find a more elegant way */
hw->samples = 4096 * 4;
hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
sizeof (st_sample_t));
if (!hw->mix_buf) {
dolog ("Could not allocate capture mix buffer (%d samples)\n",
hw->samples);
goto err2;
}
audio_pcm_init_info (&hw->info, as);
cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
if (!cap->buf) {
dolog ("Could not allocate capture buffer "
"(%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
goto err3;
}
hw->clip = mixeng_clip
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
[audio_bits_to_index (hw->info.bits)];
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
hw = NULL;
while ((hw = audio_pcm_hw_find_any_out (s, hw))) {
audio_attach_capture (s, hw);
}
return cap;
err3:
qemu_free (cap->hw.mix_buf);
err2:
qemu_free (cap);
err1:
qemu_free (cb);
err0:
return NULL;
}
}
void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
{
struct capture_callback *cb;
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
if (cb->opaque == cb_opaque) {
cb->ops.destroy (cb_opaque);
LIST_REMOVE (cb, entries);
qemu_free (cb);
if (!cap->cb_head.lh_first) {
SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
while (sw) {
SWVoiceCap *sc = (SWVoiceCap *) sw;
#ifdef DEBUG_CAPTURE
dolog ("freeing %s\n", sw->name);
#endif
sw1 = sw->entries.le_next;
if (sw->rate) {
st_rate_stop (sw->rate);
sw->rate = NULL;
}
LIST_REMOVE (sw, entries);
LIST_REMOVE (sc, entries);
qemu_free (sc);
sw = sw1;
}
LIST_REMOVE (cap, entries);
qemu_free (cap);
}
return;
}
}
}
void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol)
{
if (sw)
{
sw->vol.mute = mute;
sw->vol.l = (uint32_t)lvol * 0x808080; /* maximum is INT_MAX = 0x7fffffff */
sw->vol.r = (uint32_t)rvol * 0x808080; /* maximum is INT_MAX = 0x7fffffff */
}
}
void AUD_set_volume (audmixerctl_t mt, int *mute, uint8_t *lvol, uint8_t *rvol)
{
volume_t *vol = NULL;
const char *name;
switch (mt)
{
case AUD_MIXER_VOLUME:
name = "MASTER";
vol = &master_out_volume;
break;
case AUD_MIXER_PCM:
name = "PCM_OUT";
vol = &pcm_out_volume;
break;
case AUD_MIXER_LINE_IN:
name = "LINE_IN";
vol = &pcm_in_volume;
break;
default:
return;
}
if (vol)
{
uint32_t u32VolumeLeft = (uint32_t)*lvol;
uint32_t u32VolumeRight = (uint32_t)*rvol;
/* 0x00..0xff => 0x01..0x100 */
if (u32VolumeLeft)
u32VolumeLeft++;
if (u32VolumeRight)
u32VolumeRight++;
vol->mute = *mute;
vol->l = u32VolumeLeft * 0x800000; /* maximum is 0x80000000 */
vol->r = u32VolumeRight * 0x800000; /* maximum is 0x80000000 */
}
sum_out_volume.mute = master_out_volume.mute || pcm_out_volume.mute;
sum_out_volume.l = ASMMultU64ByU32DivByU32(master_out_volume.l, pcm_out_volume.l, 0x80000000U);
sum_out_volume.r = ASMMultU64ByU32DivByU32(master_out_volume.r, pcm_out_volume.r, 0x80000000U);
}
void AUD_set_record_source (audrecsource_t *ars, audrecsource_t *als)
{
LogRel(("Audio: set_record_source ars=%d als=%d (not implemented)\n", *ars, *als));
}
/**
* Queries an interface to the driver.
*
* @returns Pointer to interface.
* @returns NULL if the interface was not supported by the driver.
* @param pInterface Pointer to this interface structure.
* @param enmInterface The requested interface identification.
* @thread Any thread.
*/
static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface,
PDMINTERFACE enmInterface)
{
PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
PDRVAUDIO pData = PDMINS2DATA(pDrvIns, PDRVAUDIO);
switch (enmInterface)
{
case PDMINTERFACE_BASE:
return &pDrvIns->IBase;
case PDMINTERFACE_AUDIO_CONNECTOR:
return &pData->IAudioConnector;
default:
return NULL;
}
}
/**
* Power Off notification.
*
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
{
AudioState *s = &glob_audio_state;
audio_vm_change_state_handler (s, 0);
}
/**
* Destruct a driver instance.
*
* Most VM resources are freed by the VM. This callback is provided so that any non-VM
* resources can be freed correctly.
*
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
{
LogFlow(("drvAUDIODestruct:\n"));
audio_atexit ();
}
/**
* Construct an AUDIO driver instance.
*
* @returns VBox status.
* @param pDrvIns The driver instance data.
* If the registration structure is needed, pDrvIns->pDrvReg points to it.
* @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
* of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
* iInstance it's expected to be used a bit in this function.
*/
static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
{
int rc;
PDRVAUDIO pData = PDMINS2DATA(pDrvIns, PDRVAUDIO);
char *drvname;
LogFlow(("drvAUDIOConstruct:\n"));
/*
* Validate the config.
*/
if (!CFGMR3AreValuesValid(pCfgHandle, "AudioDriver\0StreamName\0"))
return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
/*
* Init the static parts.
*/
pData->pDrvIns = pDrvIns;
/* IBase */
pDrvIns->IBase.pfnQueryInterface = drvAudioQueryInterface;
/* IAudio */
/* pData->IAudioConnector.pfn; */
glob_audio_state.pDrvIns = pDrvIns;
rc = CFGMR3QueryStringAlloc (pCfgHandle, "AudioDriver", &drvname);
if (RT_FAILURE (rc))
return rc;
rc = CFGMR3QueryStringAlloc (pCfgHandle, "StreamName", &audio_streamname);
if (RT_FAILURE (rc))
audio_streamname = NULL;
rc = AUD_init (pDrvIns, drvname);
if (RT_FAILURE (rc))
return rc;
MMR3HeapFree (drvname);
return VINF_SUCCESS;
}
/**
* Suspend notification.
*
* @returns VBox status.
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) drvAudioSuspend(PPDMDRVINS pDrvIns)
{
AudioState *s = &glob_audio_state;
audio_vm_change_state_handler (s, 0);
}
/**
* Resume notification.
*
* @returns VBox status.
* @param pDrvIns The driver instance data.
*/
static DECLCALLBACK(void) audioResume(PPDMDRVINS pDrvIns)
{
AudioState *s = &glob_audio_state;
audio_vm_change_state_handler (s, 1);
}
/**
* Audio driver registration record.
*/
const PDMDRVREG g_DrvAUDIO =
{
/* u32Version */
PDM_DRVREG_VERSION,
/* szDriverName */
"AUDIO",
/* pszDescription */
"AUDIO Driver",
/* fFlags */
PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
/* fClass. */
PDM_DRVREG_CLASS_AUDIO,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(DRVAUDIO),
/* pfnConstruct */
drvAudioConstruct,
/* pfnDestruct */
drvAudioDestruct,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
drvAudioSuspend,
/* pfnResume */
audioResume,
/* pfnDetach */
NULL,
/* pfnPowerOff */
drvAudioPowerOff
};