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

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));
1.1.1.2   root       84:     rate->start_ticks = qemu_get_clock_ns (vm_clock);
1.1       root       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: 
1.1.1.2   root       94:     now = qemu_get_clock_ns (vm_clock);
1.1       root       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;
1.1.1.3 ! root      205:     case VOICE_VOLUME:
        !           206:         {
        !           207: #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
        !           208:             SWVoiceOut *sw;
        !           209:             va_list ap;
        !           210:             uint16_t vol[2];
        !           211: 
        !           212:             va_start (ap, cmd);
        !           213:             sw = va_arg (ap, SWVoiceOut *);
        !           214:             va_end (ap);
        !           215: 
        !           216:             vol[0] = sw->vol.l / ((1ULL << 16) + 1);
        !           217:             vol[1] = sw->vol.r / ((1ULL << 16) + 1);
        !           218:             spice_server_playback_set_volume (&out->sin, 2, vol);
        !           219:             spice_server_playback_set_mute (&out->sin, sw->vol.mute);
        !           220: #endif
        !           221:             break;
        !           222:         }
1.1       root      223:     }
1.1.1.3 ! root      224: 
1.1       root      225:     return 0;
                    226: }
                    227: 
                    228: /* record */
                    229: 
                    230: static int line_in_init (HWVoiceIn *hw, struct audsettings *as)
                    231: {
                    232:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
                    233:     struct audsettings settings;
                    234: 
                    235:     settings.freq       = SPICE_INTERFACE_RECORD_FREQ;
                    236:     settings.nchannels  = SPICE_INTERFACE_RECORD_CHAN;
                    237:     settings.fmt        = AUD_FMT_S16;
                    238:     settings.endianness = AUDIO_HOST_ENDIANNESS;
                    239: 
                    240:     audio_pcm_init_info (&hw->info, &settings);
                    241:     hw->samples = LINE_IN_SAMPLES;
                    242:     in->active = 0;
                    243: 
                    244:     in->sin.base.sif = &record_sif.base;
                    245:     qemu_spice_add_interface (&in->sin.base);
                    246:     return 0;
                    247: }
                    248: 
                    249: static void line_in_fini (HWVoiceIn *hw)
                    250: {
                    251:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
                    252: 
                    253:     spice_server_remove_interface (&in->sin.base);
                    254: }
                    255: 
                    256: static int line_in_run (HWVoiceIn *hw)
                    257: {
                    258:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
                    259:     int num_samples;
                    260:     int ready;
                    261:     int len[2];
                    262:     uint64_t delta_samp;
                    263:     const uint32_t *samples;
                    264: 
                    265:     if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) {
                    266:         return 0;
                    267:     }
                    268: 
                    269:     delta_samp = rate_get_samples (&hw->info, &in->rate);
                    270:     num_samples = audio_MIN (num_samples, delta_samp);
                    271: 
                    272:     ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples);
                    273:     samples = in->samples;
                    274:     if (ready == 0) {
                    275:         static const uint32_t silence[LINE_IN_SAMPLES];
                    276:         samples = silence;
                    277:         ready = LINE_IN_SAMPLES;
                    278:     }
                    279: 
                    280:     num_samples = audio_MIN (ready, num_samples);
                    281: 
                    282:     if (hw->wpos + num_samples > hw->samples) {
                    283:         len[0] = hw->samples - hw->wpos;
                    284:         len[1] = num_samples - len[0];
                    285:     } else {
                    286:         len[0] = num_samples;
                    287:         len[1] = 0;
                    288:     }
                    289: 
                    290:     hw->conv (hw->conv_buf + hw->wpos, samples, len[0]);
                    291: 
                    292:     if (len[1]) {
                    293:         hw->conv (hw->conv_buf, samples + len[0], len[1]);
                    294:     }
                    295: 
                    296:     hw->wpos = (hw->wpos + num_samples) % hw->samples;
                    297: 
                    298:     return num_samples;
                    299: }
                    300: 
                    301: static int line_in_read (SWVoiceIn *sw, void *buf, int size)
                    302: {
                    303:     return audio_pcm_sw_read (sw, buf, size);
                    304: }
                    305: 
                    306: static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)
                    307: {
                    308:     SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
                    309: 
                    310:     switch (cmd) {
                    311:     case VOICE_ENABLE:
                    312:         if (in->active) {
                    313:             break;
                    314:         }
                    315:         in->active = 1;
                    316:         rate_start (&in->rate);
                    317:         spice_server_record_start (&in->sin);
                    318:         break;
                    319:     case VOICE_DISABLE:
                    320:         if (!in->active) {
                    321:             break;
                    322:         }
                    323:         in->active = 0;
                    324:         spice_server_record_stop (&in->sin);
                    325:         break;
1.1.1.3 ! root      326:     case VOICE_VOLUME:
        !           327:         {
        !           328: #if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
        !           329:             SWVoiceIn *sw;
        !           330:             va_list ap;
        !           331:             uint16_t vol[2];
        !           332: 
        !           333:             va_start (ap, cmd);
        !           334:             sw = va_arg (ap, SWVoiceIn *);
        !           335:             va_end (ap);
        !           336: 
        !           337:             vol[0] = sw->vol.l / ((1ULL << 16) + 1);
        !           338:             vol[1] = sw->vol.r / ((1ULL << 16) + 1);
        !           339:             spice_server_record_set_volume (&in->sin, 2, vol);
        !           340:             spice_server_record_set_mute (&in->sin, sw->vol.mute);
        !           341: #endif
        !           342:             break;
        !           343:         }
1.1       root      344:     }
1.1.1.3 ! root      345: 
1.1       root      346:     return 0;
                    347: }
                    348: 
                    349: static struct audio_option audio_options[] = {
                    350:     { /* end of list */ },
                    351: };
                    352: 
                    353: static struct audio_pcm_ops audio_callbacks = {
                    354:     .init_out = line_out_init,
                    355:     .fini_out = line_out_fini,
                    356:     .run_out  = line_out_run,
                    357:     .write    = line_out_write,
                    358:     .ctl_out  = line_out_ctl,
                    359: 
                    360:     .init_in  = line_in_init,
                    361:     .fini_in  = line_in_fini,
                    362:     .run_in   = line_in_run,
                    363:     .read     = line_in_read,
                    364:     .ctl_in   = line_in_ctl,
                    365: };
                    366: 
                    367: struct audio_driver spice_audio_driver = {
                    368:     .name           = "spice",
                    369:     .descr          = "spice audio driver",
                    370:     .options        = audio_options,
                    371:     .init           = spice_audio_init,
                    372:     .fini           = spice_audio_fini,
                    373:     .pcm_ops        = &audio_callbacks,
                    374:     .max_voices_out = 1,
                    375:     .max_voices_in  = 1,
                    376:     .voice_size_out = sizeof (SpiceVoiceOut),
                    377:     .voice_size_in  = sizeof (SpiceVoiceIn),
1.1.1.3 ! root      378: #if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2))
        !           379:     .ctl_caps       = VOICE_VOLUME_CAP
        !           380: #endif
1.1       root      381: };
                    382: 
                    383: void qemu_spice_audio_init (void)
                    384: {
                    385:     spice_audio_driver.can_be_default = 1;
                    386: }

unix.superglobalmegacorp.com

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