1 | /* |
2 | * QEMU Timer based audio emulation |
3 | * |
4 | * Copyright (c) 2004-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 | #include "qemu/osdep.h" |
26 | #include "qemu/host-utils.h" |
27 | #include "qemu/module.h" |
28 | #include "audio.h" |
29 | #include "qemu/timer.h" |
30 | |
31 | #define AUDIO_CAP "noaudio" |
32 | #include "audio_int.h" |
33 | |
34 | typedef struct NoVoiceOut { |
35 | HWVoiceOut hw; |
36 | int64_t old_ticks; |
37 | } NoVoiceOut; |
38 | |
39 | typedef struct NoVoiceIn { |
40 | HWVoiceIn hw; |
41 | int64_t old_ticks; |
42 | } NoVoiceIn; |
43 | |
44 | static size_t no_run_out(HWVoiceOut *hw, size_t live) |
45 | { |
46 | NoVoiceOut *no = (NoVoiceOut *) hw; |
47 | size_t decr, samples; |
48 | int64_t now; |
49 | int64_t ticks; |
50 | int64_t bytes; |
51 | |
52 | now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
53 | ticks = now - no->old_ticks; |
54 | bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND); |
55 | bytes = MIN(bytes, SIZE_MAX); |
56 | samples = bytes >> hw->info.shift; |
57 | |
58 | no->old_ticks = now; |
59 | decr = MIN (live, samples); |
60 | hw->rpos = (hw->rpos + decr) % hw->samples; |
61 | return decr; |
62 | } |
63 | |
64 | static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque) |
65 | { |
66 | audio_pcm_init_info (&hw->info, as); |
67 | hw->samples = 1024; |
68 | return 0; |
69 | } |
70 | |
71 | static void no_fini_out (HWVoiceOut *hw) |
72 | { |
73 | (void) hw; |
74 | } |
75 | |
76 | static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) |
77 | { |
78 | (void) hw; |
79 | (void) cmd; |
80 | return 0; |
81 | } |
82 | |
83 | static int no_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) |
84 | { |
85 | audio_pcm_init_info (&hw->info, as); |
86 | hw->samples = 1024; |
87 | return 0; |
88 | } |
89 | |
90 | static void no_fini_in (HWVoiceIn *hw) |
91 | { |
92 | (void) hw; |
93 | } |
94 | |
95 | static size_t no_run_in(HWVoiceIn *hw) |
96 | { |
97 | NoVoiceIn *no = (NoVoiceIn *) hw; |
98 | size_t live = audio_pcm_hw_get_live_in(hw); |
99 | size_t dead = hw->samples - live; |
100 | size_t samples = 0; |
101 | |
102 | if (dead) { |
103 | int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); |
104 | int64_t ticks = now - no->old_ticks; |
105 | int64_t bytes = |
106 | muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND); |
107 | |
108 | no->old_ticks = now; |
109 | bytes = MIN (bytes, SIZE_MAX); |
110 | samples = bytes >> hw->info.shift; |
111 | samples = MIN (samples, dead); |
112 | } |
113 | return samples; |
114 | } |
115 | |
116 | static int no_ctl_in (HWVoiceIn *hw, int cmd, ...) |
117 | { |
118 | (void) hw; |
119 | (void) cmd; |
120 | return 0; |
121 | } |
122 | |
123 | static void *no_audio_init(Audiodev *dev) |
124 | { |
125 | return &no_audio_init; |
126 | } |
127 | |
128 | static void no_audio_fini (void *opaque) |
129 | { |
130 | (void) opaque; |
131 | } |
132 | |
133 | static struct audio_pcm_ops no_pcm_ops = { |
134 | .init_out = no_init_out, |
135 | .fini_out = no_fini_out, |
136 | .run_out = no_run_out, |
137 | .ctl_out = no_ctl_out, |
138 | |
139 | .init_in = no_init_in, |
140 | .fini_in = no_fini_in, |
141 | .run_in = no_run_in, |
142 | .ctl_in = no_ctl_in |
143 | }; |
144 | |
145 | static struct audio_driver no_audio_driver = { |
146 | .name = "none" , |
147 | .descr = "Timer based audio emulation" , |
148 | .init = no_audio_init, |
149 | .fini = no_audio_fini, |
150 | .pcm_ops = &no_pcm_ops, |
151 | .can_be_default = 1, |
152 | .max_voices_out = INT_MAX, |
153 | .max_voices_in = INT_MAX, |
154 | .voice_size_out = sizeof (NoVoiceOut), |
155 | .voice_size_in = sizeof (NoVoiceIn) |
156 | }; |
157 | |
158 | static void register_audio_none(void) |
159 | { |
160 | audio_driver_register(&no_audio_driver); |
161 | } |
162 | type_init(register_audio_none); |
163 | |