Annotation of qemu/audio/spiceaudio.c, revision 1.1.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.