| 1 | /* |
| 2 | * QEMU Audio subsystem header |
| 3 | * |
| 4 | * Copyright (c) 2003-2005 Vassili Karpov (malc) |
| 5 | * |
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to deal |
| 8 | * in the Software without restriction, including without limitation the rights |
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | * copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in |
| 14 | * all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. |
| 23 | */ |
| 24 | |
| 25 | #ifndef QEMU_AUDIO_INT_H |
| 26 | #define QEMU_AUDIO_INT_H |
| 27 | |
| 28 | #ifdef CONFIG_AUDIO_COREAUDIO |
| 29 | #define FLOAT_MIXENG |
| 30 | /* #define RECIPROCAL */ |
| 31 | #endif |
| 32 | #include "qemu/audio.h" |
| 33 | #include "qemu/audio-capture.h" |
| 34 | #include "mixeng.h" |
| 35 | |
| 36 | struct audio_callback { |
| 37 | void *opaque; |
| 38 | audio_callback_fn fn; |
| 39 | }; |
| 40 | |
| 41 | struct audio_pcm_info { |
| 42 | AudioFormat af; |
| 43 | int freq; |
| 44 | int nchannels; |
| 45 | int bytes_per_frame; |
| 46 | int bytes_per_second; |
| 47 | int swap_endianness; |
| 48 | }; |
| 49 | |
| 50 | typedef struct AudioMixengBackend AudioMixengBackend; |
| 51 | typedef struct SWVoiceCap SWVoiceCap; |
| 52 | |
| 53 | typedef struct STSampleBuffer { |
| 54 | size_t pos, size; |
| 55 | st_sample *buffer; |
| 56 | } STSampleBuffer; |
| 57 | |
| 58 | typedef struct HWVoiceOut { |
| 59 | AudioMixengBackend *s; |
| 60 | bool enabled; |
| 61 | int poll_mode; |
| 62 | bool pending_disable; |
| 63 | struct audio_pcm_info info; |
| 64 | |
| 65 | f_sample *clip; |
| 66 | |
| 67 | STSampleBuffer mix_buf; |
| 68 | void *buf_emul; |
| 69 | size_t pos_emul, pending_emul, size_emul; |
| 70 | |
| 71 | size_t samples; |
| 72 | QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; |
| 73 | QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; |
| 74 | QLIST_ENTRY (HWVoiceOut) entries; |
| 75 | } HWVoiceOut; |
| 76 | |
| 77 | typedef struct HWVoiceIn { |
| 78 | AudioMixengBackend *s; |
| 79 | bool enabled; |
| 80 | int poll_mode; |
| 81 | struct audio_pcm_info info; |
| 82 | |
| 83 | t_sample *conv; |
| 84 | |
| 85 | size_t total_samples_captured; |
| 86 | |
| 87 | STSampleBuffer conv_buf; |
| 88 | void *buf_emul; |
| 89 | size_t pos_emul, pending_emul, size_emul; |
| 90 | |
| 91 | size_t samples; |
| 92 | QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; |
| 93 | QLIST_ENTRY (HWVoiceIn) entries; |
| 94 | } HWVoiceIn; |
| 95 | |
| 96 | struct SWVoiceOut { |
| 97 | AudioMixengBackend *s; |
| 98 | struct audio_pcm_info info; |
| 99 | t_sample *conv; |
| 100 | STSampleBuffer resample_buf; |
| 101 | void *rate; |
| 102 | size_t total_hw_samples_mixed; |
| 103 | bool active; |
| 104 | bool empty; |
| 105 | HWVoiceOut *hw; |
| 106 | char *name; |
| 107 | struct mixeng_volume vol; |
| 108 | struct audio_callback callback; |
| 109 | QLIST_ENTRY (SWVoiceOut) entries; |
| 110 | }; |
| 111 | |
| 112 | struct SWVoiceIn { |
| 113 | AudioMixengBackend *s; |
| 114 | bool active; |
| 115 | struct audio_pcm_info info; |
| 116 | void *rate; |
| 117 | size_t total_hw_samples_acquired; |
| 118 | STSampleBuffer resample_buf; |
| 119 | f_sample *clip; |
| 120 | HWVoiceIn *hw; |
| 121 | char *name; |
| 122 | struct mixeng_volume vol; |
| 123 | struct audio_callback callback; |
| 124 | QLIST_ENTRY (SWVoiceIn) entries; |
| 125 | }; |
| 126 | |
| 127 | audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo); |
| 128 | int audioformat_bytes_per_sample(AudioFormat fmt); |
| 129 | int audio_buffer_frames(AudiodevPerDirectionOptions *pdo, |
| 130 | audsettings *as, int def_usecs); |
| 131 | int audio_buffer_samples(AudiodevPerDirectionOptions *pdo, |
| 132 | audsettings *as, int def_usecs); |
| 133 | int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo, |
| 134 | audsettings *as, int def_usecs); |
| 135 | |
| 136 | static inline void *advance(void *p, size_t incr) |
| 137 | { |
| 138 | return (uint8_t *)p + incr; |
| 139 | } |
| 140 | |
| 141 | int wav_start_capture(AudioBackend *state, CaptureState *s, const char *path, |
| 142 | int freq, int bits, int nchannels); |
| 143 | |
| 144 | void audio_generic_initialize_buffer_in(HWVoiceIn *hw); |
| 145 | void audio_generic_run_buffer_in(HWVoiceIn *hw); |
| 146 | void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size); |
| 147 | void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size); |
| 148 | void audio_generic_initialize_buffer_out(HWVoiceOut *hw); |
| 149 | void audio_generic_run_buffer_out(HWVoiceOut *hw); |
| 150 | size_t audio_generic_buffer_get_free(HWVoiceOut *hw); |
| 151 | void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size); |
| 152 | size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size); |
| 153 | size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size); |
| 154 | size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size); |
| 155 | |
| 156 | struct capture_callback { |
| 157 | struct audio_capture_ops ops; |
| 158 | void *opaque; |
| 159 | QLIST_ENTRY (capture_callback) entries; |
| 160 | }; |
| 161 | |
| 162 | struct CaptureVoiceOut { |
| 163 | HWVoiceOut hw; |
| 164 | void *buf; |
| 165 | QLIST_HEAD (cb_listhead, capture_callback) cb_head; |
| 166 | QLIST_ENTRY (CaptureVoiceOut) entries; |
| 167 | }; |
| 168 | |
| 169 | struct SWVoiceCap { |
| 170 | SWVoiceOut sw; |
| 171 | CaptureVoiceOut *cap; |
| 172 | QLIST_ENTRY (SWVoiceCap) entries; |
| 173 | }; |
| 174 | |
| 175 | struct AudioMixengBackendClass { |
| 176 | AudioBackendClass parent_class; |
| 177 | |
| 178 | int max_voices_out; |
| 179 | int max_voices_in; |
| 180 | size_t voice_size_out; |
| 181 | size_t voice_size_in; |
| 182 | |
| 183 | int (*init_out)(HWVoiceOut *hw, audsettings *as); |
| 184 | void (*fini_out)(HWVoiceOut *hw); |
| 185 | size_t (*write) (HWVoiceOut *hw, void *buf, size_t size); |
| 186 | void (*run_buffer_out)(HWVoiceOut *hw); |
| 187 | /* |
| 188 | * Get the free output buffer size. This is an upper limit. The size |
| 189 | * returned by function get_buffer_out may be smaller. |
| 190 | */ |
| 191 | size_t (*buffer_get_free)(HWVoiceOut *hw); |
| 192 | /* |
| 193 | * get a buffer that after later can be passed to put_buffer_out; optional |
| 194 | * returns the buffer, and writes it's size to size (in bytes) |
| 195 | */ |
| 196 | void *(*get_buffer_out)(HWVoiceOut *hw, size_t *size); |
| 197 | /* |
| 198 | * put back the buffer returned by get_buffer_out; optional |
| 199 | * buf must be equal the pointer returned by get_buffer_out, |
| 200 | * size may be smaller |
| 201 | */ |
| 202 | size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size); |
| 203 | void (*enable_out)(HWVoiceOut *hw, bool enable); |
| 204 | void (*volume_out)(HWVoiceOut *hw, Volume *vol); |
| 205 | |
| 206 | int (*init_in) (HWVoiceIn *hw, audsettings *as); |
| 207 | void (*fini_in) (HWVoiceIn *hw); |
| 208 | size_t (*read) (HWVoiceIn *hw, void *buf, size_t size); |
| 209 | void (*run_buffer_in)(HWVoiceIn *hw); |
| 210 | void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size); |
| 211 | void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size); |
| 212 | void (*enable_in)(HWVoiceIn *hw, bool enable); |
| 213 | void (*volume_in)(HWVoiceIn *hw, Volume *vol); |
| 214 | }; |
| 215 | |
| 216 | struct AudioMixengBackend { |
| 217 | AudioBackend parent_obj; |
| 218 | |
| 219 | Audiodev *dev; |
| 220 | |
| 221 | QEMUTimer *ts; |
| 222 | GTimer *run_timer; |
| 223 | QLIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; |
| 224 | QLIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; |
| 225 | QLIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head; |
| 226 | int nb_hw_voices_out; |
| 227 | int nb_hw_voices_in; |
| 228 | int64_t period_ticks; |
| 229 | |
| 230 | bool timer_running; |
| 231 | uint64_t timer_last; |
| 232 | VMChangeStateEntry *vmse; |
| 233 | }; |
| 234 | |
| 235 | extern const struct mixeng_volume nominal_volume; |
| 236 | |
| 237 | extern const char *audio_prio_list[]; |
| 238 | |
| 239 | void audio_pcm_init_info (struct audio_pcm_info *info, const struct audsettings *as); |
| 240 | void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); |
| 241 | |
| 242 | void audio_run(AudioMixengBackend *s, const char *msg); |
| 243 | |
| 244 | typedef struct RateCtl { |
| 245 | int64_t start_ticks; |
| 246 | int64_t bytes_sent; |
| 247 | int64_t peeked_frames; |
| 248 | } RateCtl; |
| 249 | |
| 250 | void audio_rate_start(RateCtl *rate); |
| 251 | size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info); |
| 252 | void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used); |
| 253 | size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info, |
| 254 | size_t bytes_avail); |
| 255 | |
| 256 | static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len) |
| 257 | { |
| 258 | return (dst >= src) ? (dst - src) : (len - src + dst); |
| 259 | } |
| 260 | |
| 261 | /** |
| 262 | * audio_ring_posb() - returns new position in ringbuffer in backward |
| 263 | * direction at given distance |
| 264 | * |
| 265 | * @pos: current position in ringbuffer |
| 266 | * @dist: distance in ringbuffer to walk in reverse direction |
| 267 | * @len: size of ringbuffer |
| 268 | */ |
| 269 | static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len) |
| 270 | { |
| 271 | return pos >= dist ? pos - dist : len - dist + pos; |
| 272 | } |
| 273 | |
| 274 | AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev); |
| 275 | AudiodevPerDirectionOptions *audio_get_pdo_out(Audiodev *dev); |
| 276 | |
| 277 | void audio_sample_to_uint64(const st_sample *sample, int pos, |
| 278 | uint64_t *left, uint64_t *right); |
| 279 | void audio_sample_from_uint64(st_sample *sample, int pos, |
| 280 | uint64_t left, uint64_t right); |
| 281 | |
| 282 | #define TYPE_AUDIO_MIXENG_BACKEND "audio-mixeng-backend" |
| 283 | OBJECT_DECLARE_TYPE(AudioMixengBackend, AudioMixengBackendClass, AUDIO_MIXENG_BACKEND) |
| 284 | |
| 285 | #endif /* QEMU_AUDIO_INT_H */ |