Annotation of qemu/audio/spiceaudio.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2010 Red Hat, Inc.
        !             3:  *
        !             4:  * maintained by Gerd Hoffmann <[email protected]>
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or
        !             7:  * modify it under the terms of the GNU General Public License as
        !             8:  * published by the Free Software Foundation; either version 2 or
        !             9:  * (at your option) version 3 of the License.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful,
        !            12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14:  * GNU General Public License for more details.
        !            15:  *
        !            16:  * You should have received a copy of the GNU General Public License
        !            17:  * along with this program; if not, see <http://www.gnu.org/licenses/>.
        !            18:  */
        !            19: 
        !            20: #include "hw/hw.h"
        !            21: #include "qemu-timer.h"
        !            22: #include "ui/qemu-spice.h"
        !            23: 
        !            24: #define AUDIO_CAP "spice"
        !            25: #include "audio.h"
        !            26: #include "audio_int.h"
        !            27: 
        !            28: #define LINE_IN_SAMPLES 1024
        !            29: #define LINE_OUT_SAMPLES 1024
        !            30: 
        !            31: typedef struct SpiceRateCtl {
        !            32:     int64_t               start_ticks;
        !            33:     int64_t               bytes_sent;
        !            34: } SpiceRateCtl;
        !            35: 
        !            36: typedef struct SpiceVoiceOut {
        !            37:     HWVoiceOut            hw;
        !            38:     SpicePlaybackInstance sin;
        !            39:     SpiceRateCtl          rate;
        !            40:     int                   active;
        !            41:     uint32_t              *frame;
        !            42:     uint32_t              *fpos;
        !            43:     uint32_t              fsize;
        !            44: } SpiceVoiceOut;
        !            45: 
        !            46: typedef struct SpiceVoiceIn {
        !            47:     HWVoiceIn             hw;
        !            48:     SpiceRecordInstance   sin;
        !            49:     SpiceRateCtl          rate;
        !            50:     int                   active;
        !            51:     uint32_t              samples[LINE_IN_SAMPLES];
        !            52: } SpiceVoiceIn;
        !            53: 
        !            54: static const SpicePlaybackInterface playback_sif = {
        !            55:     .base.type          = SPICE_INTERFACE_PLAYBACK,
        !            56:     .base.description   = "playback",
        !            57:     .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR,
        !            58:     .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR,
        !            59: };
        !            60: 
        !            61: static const SpiceRecordInterface record_sif = {
        !            62:     .base.type          = SPICE_INTERFACE_RECORD,
        !            63:     .base.description   = "record",
        !            64:     .base.major_version = SPICE_INTERFACE_RECORD_MAJOR,
        !            65:     .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
        !            66: };
        !            67: 
        !            68: static void *spice_audio_init (void)
        !            69: {
        !            70:     if (!using_spice) {
        !            71:         return NULL;
        !            72:     }
        !            73:     return &spice_audio_init;
        !            74: }
        !            75: 
        !            76: static void spice_audio_fini (void *opaque)
        !            77: {
        !            78:     /* nothing */
        !            79: }
        !            80: 
        !            81: static void rate_start (SpiceRateCtl *rate)
        !            82: {
        !            83:     memset (rate, 0, sizeof (*rate));
        !            84:     rate->start_ticks = qemu_get_clock (vm_clock);
        !            85: }
        !            86: 
        !            87: static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate)
        !            88: {
        !            89:     int64_t now;
        !            90:     int64_t ticks;
        !            91:     int64_t bytes;
        !            92:     int64_t samples;
        !            93: 
        !            94:     now = qemu_get_clock (vm_clock);
        !            95:     ticks = now - rate->start_ticks;
        !            96:     bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ());
        !            97:     samples = (bytes - rate->bytes_sent) >> info->shift;
        !            98:     if (samples < 0 || samples > 65536) {
        !            99:         fprintf (stderr, "Resetting rate control (%" PRId64 " samples)\n", samples);
        !           100:         rate_start (rate);
        !           101:         samples = 0;
        !           102:     }
        !           103:     rate->bytes_sent += samples << info->shift;
        !           104:     return samples;
        !           105: }
        !           106: 
        !           107: /* playback */
        !           108: 
        !           109: static int line_out_init (HWVoiceOut *hw, struct audsettings *as)
        !           110: {
        !           111:     SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
        !           112:     struct audsettings settings;
        !           113: 
        !           114:     settings.freq       = SPICE_INTERFACE_PLAYBACK_FREQ;
        !           115:     settings.nchannels  = SPICE_INTERFACE_PLAYBACK_CHAN;
        !           116:     settings.fmt        = AUD_FMT_S16;
        !           117:     settings.endianness = AUDIO_HOST_ENDIANNESS;
        !           118: 
        !           119:     audio_pcm_init_info (&hw->info, &settings);
        !           120:     hw->samples = LINE_OUT_SAMPLES;
        !           121:     out->active = 0;
        !           122: 
        !           123:     out->sin.base.sif = &playback_sif.base;
        !           124:     qemu_spice_add_interface (&out->sin.base);
        !           125:     return 0;
        !           126: }
        !           127: 
        !           128: static void line_out_fini (HWVoiceOut *hw)
        !           129: {
        !           130:     SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
        !           131: 
        !           132:     spice_server_remove_interface (&out->sin.base);
        !           133: }
        !           134: 
        !           135: static int line_out_run (HWVoiceOut *hw, int live)
        !           136: {
        !           137:     SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
        !           138:     int rpos, decr;
        !           139:     int samples;
        !           140: 
        !           141:     if (!live) {
        !           142:         return 0;
        !           143:     }
        !           144: 
        !           145:     decr = rate_get_samples (&hw->info, &out->rate);
        !           146:     decr = audio_MIN (live, decr);
        !           147: 
        !           148:     samples = decr;
        !           149:     rpos = hw->rpos;
        !           150:     while (samples) {
        !           151:         int left_till_end_samples = hw->samples - rpos;
        !           152:         int len = audio_MIN (samples, left_till_end_samples);
        !           153: 
        !           154:         if (!out->frame) {
        !           155:             spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize);
        !           156:             out->fpos = out->frame;
        !           157:         }
        !           158:         if (out->frame) {
        !           159:             len = audio_MIN (len, out->fsize);
        !           160:             hw->clip (out->fpos, hw->mix_buf + rpos, len);
        !           161:             out->fsize -= len;
        !           162:             out->fpos  += len;
        !           163:             if (out->fsize == 0) {
        !           164:                 spice_server_playback_put_samples (&out->sin, out->frame);
        !           165:                 out->frame = out->fpos = NULL;
        !           166:             }
        !           167:         }
        !           168:         rpos = (rpos + len) % hw->samples;
        !           169:         samples -= len;
        !           170:     }
        !           171:     hw->rpos = rpos;
        !           172:     return decr;
        !           173: }
        !           174: 
        !           175: static int line_out_write (SWVoiceOut *sw, void *buf, int len)
        !           176: {
        !           177:     return audio_pcm_sw_write (sw, buf, len);
        !           178: }
        !           179: 
        !           180: static int line_out_ctl (HWVoiceOut *hw, int cmd, ...)
        !           181: {
        !           182:     SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw);
        !           183: 
        !           184:     switch (cmd) {
        !           185:     case VOICE_ENABLE:
        !           186:         if (out->active) {
        !           187:             break;
        !           188:         }
        !           189:         out->active = 1;
        !           190:         rate_start (&out->rate);
        !           191:         spice_server_playback_start (&out->sin);
        !           192:         break;
        !           193:     case VOICE_DISABLE:
        !           194:         if (!out->active) {
        !           195:             break;
        !           196:         }
        !           197:         out->active = 0;
        !           198:         if (out->frame) {
        !           199:             memset (out->fpos, 0, out->fsize << 2);
        !           200:             spice_server_playback_put_samples (&out->sin, out->frame);
        !           201:             out->frame = out->fpos = NULL;
        !           202:         }
        !           203:         spice_server_playback_stop (&out->sin);
        !           204:         break;
        !           205:     }
        !           206:     return 0;
        !           207: }
        !           208: 
        !           209: /* record */
        !           210: 
        !           211: static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
        !           212: {
        !           213:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
        !           214:     struct audsettings settings;
        !           215: 
        !           216:     settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
        !           217:     settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
        !           218:     settings.fmt        = AUD_FMT_S16;
        !           219:     settings.endianness = AUDIO_HOST_ENDIANNESS;
        !           220: 
        !           221:     audio_pcm_init_info (&hw->info, &settings);
        !           222:     hw->samples = LINE_IN_SAMPLES;
        !           223:     in->active = 0;
        !           224: 
        !           225:     in->sin.base.sif = &record_sif.base;
        !           226:     qemu_spice_add_interface (&in->sin.base);
        !           227:     return 0;
        !           228: }
        !           229: 
        !           230: static void line_in_fini (HWVoiceIn *hw)
        !           231: {
        !           232:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
        !           233: 
        !           234:     spice_server_remove_interface (&in->sin.base);
        !           235: }
        !           236: 
        !           237: static int line_in_run (HWVoiceIn *hw)
        !           238: {
        !           239:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
        !           240:     int num_samples;
        !           241:     int ready;
        !           242:     int len[2];
        !           243:     uint64_t delta_samp;
        !           244:     const uint32_t *samples;
        !           245: 
        !           246:     if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
        !           247:         return 0;
        !           248:     }
        !           249: 
        !           250:     delta_samp = rate_get_samples (&hw->info, &in->rate);
        !           251:     num_samples = audio_MIN (num_samples, delta_samp);
        !           252: 
        !           253:     ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
        !           254:     samples = in->samples;
        !           255:     if (ready == 0) {
        !           256:         static const uint32_t silence[LINE_IN_SAMPLES];
        !           257:         samples = silence;
        !           258:         ready = LINE_IN_SAMPLES;
        !           259:     }
        !           260: 
        !           261:     num_samples = audio_MIN (ready, num_samples);
        !           262: 
        !           263:     if (hw->wpos + num_samples > hw->samples) {
        !           264:         len[0] = hw->samples - hw->wpos;
        !           265:         len[1] = num_samples - len[0];
        !           266:     } else {
        !           267:         len[0] = num_samples;
        !           268:         len[1] = 0;
        !           269:     }
        !           270: 
        !           271:     hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
        !           272: 
        !           273:     if (len[1]) {
        !           274:         hw->conv (hw->conv_buf, samples + len[0], len[1]);
        !           275:     }
        !           276: 
        !           277:     hw->wpos = (hw->wpos + num_samples) % hw->samples;
        !           278: 
        !           279:     return num_samples;
        !           280: }
        !           281: 
        !           282: static int line_in_read (SWVoiceIn *sw, void *buf, int size)
        !           283: {
        !           284:     return audio_pcm_sw_read (sw, buf, size);
        !           285: }
        !           286: 
        !           287: static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
        !           288: {
        !           289:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
        !           290: 
        !           291:     switch (cmd) {
        !           292:     case VOICE_ENABLE:
        !           293:         if (in->active) {
        !           294:             break;
        !           295:         }
        !           296:         in->active = 1;
        !           297:         rate_start (&in->rate);
        !           298:         spice_server_record_start (&in->sin);
        !           299:         break;
        !           300:     case VOICE_DISABLE:
        !           301:         if (!in->active) {
        !           302:             break;
        !           303:         }
        !           304:         in->active = 0;
        !           305:         spice_server_record_stop (&in->sin);
        !           306:         break;
        !           307:     }
        !           308:     return 0;
        !           309: }
        !           310: 
        !           311: static struct audio_option audio_options[] = {
        !           312:     { /* end of list */ },
        !           313: };
        !           314: 
        !           315: static struct audio_pcm_ops audio_callbacks = {
        !           316:     .init_out = line_out_init,
        !           317:     .fini_out = line_out_fini,
        !           318:     .run_out  = line_out_run,
        !           319:     .write    = line_out_write,
        !           320:     .ctl_out  = line_out_ctl,
        !           321: 
        !           322:     .init_in  = line_in_init,
        !           323:     .fini_in  = line_in_fini,
        !           324:     .run_in   = line_in_run,
        !           325:     .read     = line_in_read,
        !           326:     .ctl_in   = line_in_ctl,
        !           327: };
        !           328: 
        !           329: struct audio_driver spice_audio_driver = {
        !           330:     .name           = "spice",
        !           331:     .descr          = "spice audio driver",
        !           332:     .options        = audio_options,
        !           333:     .init           = spice_audio_init,
        !           334:     .fini           = spice_audio_fini,
        !           335:     .pcm_ops        = &audio_callbacks,
        !           336:     .max_voices_out = 1,
        !           337:     .max_voices_in  = 1,
        !           338:     .voice_size_out = sizeof (SpiceVoiceOut),
        !           339:     .voice_size_in  = sizeof (SpiceVoiceIn),
        !           340: };
        !           341: 
        !           342: void qemu_spice_audio_init (void)
        !           343: {
        !           344:     spice_audio_driver.can_be_default = 1;
        !           345: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.