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 | #include "VBoxDD.h"
|
---|
25 | #include "vl_vbox.h"
|
---|
26 | #include "audio.h"
|
---|
27 | #include <iprt/alloc.h>
|
---|
28 |
|
---|
29 | #define AUDIO_CAP "noaudio"
|
---|
30 | #include "audio_int.h"
|
---|
31 |
|
---|
32 | typedef struct NoVoiceOut {
|
---|
33 | HWVoiceOut hw;
|
---|
34 | int64_t old_ticks;
|
---|
35 | } NoVoiceOut;
|
---|
36 |
|
---|
37 | typedef struct NoVoiceIn {
|
---|
38 | HWVoiceIn hw;
|
---|
39 | int64_t old_ticks;
|
---|
40 | } NoVoiceIn;
|
---|
41 |
|
---|
42 | static int no_run_out (HWVoiceOut *hw)
|
---|
43 | {
|
---|
44 | NoVoiceOut *no = (NoVoiceOut *) hw;
|
---|
45 | int live, decr, samples;
|
---|
46 | int64_t now;
|
---|
47 | int64_t ticks;
|
---|
48 | int64_t ticks_per_second;
|
---|
49 |
|
---|
50 | live = audio_pcm_hw_get_live_out (&no->hw);
|
---|
51 | if (!live) {
|
---|
52 | return 0;
|
---|
53 | }
|
---|
54 |
|
---|
55 | now = audio_get_clock ();
|
---|
56 | ticks = now - no->old_ticks;
|
---|
57 |
|
---|
58 | ticks_per_second = audio_get_ticks_per_sec ();
|
---|
59 | /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
|
---|
60 | samples = (int)((2 * ticks * hw->info.freq + ticks_per_second) / ticks_per_second / 2);
|
---|
61 | /* Usually there is no integer overflow while calculating the 'samples' value.
|
---|
62 | * It can happen because this is the first invocation or because the function was not called for awhile.
|
---|
63 | * In this case simply claim that all samples has been played.
|
---|
64 | */
|
---|
65 | if (samples < 0) {
|
---|
66 | samples = live;
|
---|
67 | }
|
---|
68 |
|
---|
69 | no->old_ticks = now;
|
---|
70 | decr = audio_MIN (live, samples);
|
---|
71 | hw->rpos = (hw->rpos + decr) % hw->samples;
|
---|
72 | return decr;
|
---|
73 | }
|
---|
74 |
|
---|
75 | static int no_write (SWVoiceOut *sw, void *buf, int len)
|
---|
76 | {
|
---|
77 | return audio_pcm_sw_write (sw, buf, len);
|
---|
78 | }
|
---|
79 |
|
---|
80 | static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
|
---|
81 | {
|
---|
82 | audio_pcm_init_info (&hw->info, as);
|
---|
83 | hw->samples = 1024;
|
---|
84 | return 0;
|
---|
85 | }
|
---|
86 |
|
---|
87 | static void no_fini_out (HWVoiceOut *hw)
|
---|
88 | {
|
---|
89 | (void) hw;
|
---|
90 | }
|
---|
91 |
|
---|
92 | static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
---|
93 | {
|
---|
94 | (void) hw;
|
---|
95 | (void) cmd;
|
---|
96 | return 0;
|
---|
97 | }
|
---|
98 |
|
---|
99 | static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
|
---|
100 | {
|
---|
101 | audio_pcm_init_info (&hw->info, as);
|
---|
102 | hw->samples = 1024;
|
---|
103 | return 0;
|
---|
104 | }
|
---|
105 |
|
---|
106 | static void no_fini_in (HWVoiceIn *hw)
|
---|
107 | {
|
---|
108 | (void) hw;
|
---|
109 | }
|
---|
110 |
|
---|
111 | static int no_run_in (HWVoiceIn *hw)
|
---|
112 | {
|
---|
113 | NoVoiceIn *no = (NoVoiceIn *) hw;
|
---|
114 | int live = audio_pcm_hw_get_live_in (hw);
|
---|
115 | int dead = hw->samples - live;
|
---|
116 | int samples = 0;
|
---|
117 |
|
---|
118 | if (dead) {
|
---|
119 | int64_t now = audio_get_clock ();
|
---|
120 | int64_t ticks = now - no->old_ticks;
|
---|
121 | int64_t bytes = (ticks * hw->info.bytes_per_second)
|
---|
122 | / audio_get_ticks_per_sec ();
|
---|
123 |
|
---|
124 | no->old_ticks = now;
|
---|
125 | bytes = audio_MIN (bytes, INT_MAX);
|
---|
126 | samples = bytes >> hw->info.shift;
|
---|
127 | samples = audio_MIN (samples, dead);
|
---|
128 | hw->wpos = (hw->wpos + samples) % hw->samples;
|
---|
129 | }
|
---|
130 | return samples;
|
---|
131 | }
|
---|
132 |
|
---|
133 | static int no_read (SWVoiceIn *sw, void *buf, int size)
|
---|
134 | {
|
---|
135 | return audio_pcm_sw_read (sw, buf, size);
|
---|
136 | }
|
---|
137 |
|
---|
138 | static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
|
---|
139 | {
|
---|
140 | (void) hw;
|
---|
141 | (void) cmd;
|
---|
142 | return 0;
|
---|
143 | }
|
---|
144 |
|
---|
145 | static void *no_audio_init (void)
|
---|
146 | {
|
---|
147 | return &no_audio_driver;
|
---|
148 | }
|
---|
149 |
|
---|
150 | static void no_audio_fini (void *opaque)
|
---|
151 | {
|
---|
152 | (void) opaque;
|
---|
153 | }
|
---|
154 |
|
---|
155 | static struct audio_pcm_ops no_pcm_ops = {
|
---|
156 | no_init_out,
|
---|
157 | no_fini_out,
|
---|
158 | no_run_out,
|
---|
159 | no_write,
|
---|
160 | no_ctl_out,
|
---|
161 |
|
---|
162 | no_init_in,
|
---|
163 | no_fini_in,
|
---|
164 | no_run_in,
|
---|
165 | no_read,
|
---|
166 | no_ctl_in
|
---|
167 | };
|
---|
168 |
|
---|
169 | struct audio_driver no_audio_driver = {
|
---|
170 | INIT_FIELD (name = ) "null",
|
---|
171 | INIT_FIELD (descr = ) "Timer based audio emulation",
|
---|
172 | INIT_FIELD (options = ) NULL,
|
---|
173 | INIT_FIELD (init = ) no_audio_init,
|
---|
174 | INIT_FIELD (fini = ) no_audio_fini,
|
---|
175 | INIT_FIELD (pcm_ops = ) &no_pcm_ops,
|
---|
176 | INIT_FIELD (can_be_default = ) 1,
|
---|
177 | INIT_FIELD (max_voices_out = ) INT_MAX,
|
---|
178 | INIT_FIELD (max_voices_in = ) INT_MAX,
|
---|
179 | INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut),
|
---|
180 | INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn)
|
---|
181 | };
|
---|