1 |
/* |
/* |
2 |
* QEMU NULL audio output driver |
* QEMU Timer based audio emulation |
3 |
* |
* |
4 |
* Copyright (c) 2004 Vassili Karpov (malc) |
* Copyright (c) 2004-2005 Vassili Karpov (malc) |
5 |
* |
* |
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
* 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 |
* of this software and associated documentation files (the "Software"), to deal |
8 |
* in the Software without restriction, including without limitation the rights |
* in the Software without restriction, including without limitation the rights |
23 |
*/ |
*/ |
24 |
#include "vl.h" |
#include "vl.h" |
25 |
|
|
26 |
#include "audio/audio_int.h" |
#define AUDIO_CAP "noaudio" |
27 |
|
#include "audio_int.h" |
28 |
|
|
29 |
|
typedef struct NoVoiceOut { |
30 |
|
HWVoiceOut hw; |
31 |
|
int64_t old_ticks; |
32 |
|
} NoVoiceOut; |
33 |
|
|
34 |
typedef struct NoVoice { |
typedef struct NoVoiceIn { |
35 |
HWVoice hw; |
HWVoiceIn hw; |
36 |
int64_t old_ticks; |
int64_t old_ticks; |
37 |
} NoVoice; |
} NoVoiceIn; |
38 |
|
|
39 |
#define dolog(...) AUD_log ("noaudio", __VA_ARGS__) |
static int no_run_out (HWVoiceOut *hw) |
40 |
#ifdef DEBUG |
{ |
41 |
#define ldebug(...) dolog (__VA_ARGS__) |
NoVoiceOut *no = (NoVoiceOut *) hw; |
42 |
#else |
int live, decr, samples; |
|
#define ldebug(...) |
|
|
#endif |
|
|
|
|
|
static void no_hw_run (HWVoice *hw) |
|
|
{ |
|
|
NoVoice *no = (NoVoice *) hw; |
|
|
int rpos, live, decr, samples; |
|
|
st_sample_t *src; |
|
43 |
int64_t now = qemu_get_clock (vm_clock); |
int64_t now = qemu_get_clock (vm_clock); |
44 |
int64_t ticks = now - no->old_ticks; |
int64_t ticks = now - no->old_ticks; |
45 |
int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec; |
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; |
46 |
|
|
47 |
|
if (bytes > INT_MAX) { |
48 |
|
samples = INT_MAX >> hw->info.shift; |
49 |
|
} |
50 |
|
else { |
51 |
|
samples = bytes >> hw->info.shift; |
52 |
|
} |
53 |
|
|
54 |
if (bytes > INT_MAX) |
live = audio_pcm_hw_get_live_out (&no->hw); |
55 |
samples = INT_MAX >> hw->shift; |
if (!live) { |
56 |
else |
return 0; |
57 |
samples = bytes >> hw->shift; |
} |
|
|
|
|
live = pcm_hw_get_live (hw); |
|
|
if (live <= 0) |
|
|
return; |
|
58 |
|
|
59 |
no->old_ticks = now; |
no->old_ticks = now; |
60 |
decr = audio_MIN (live, samples); |
decr = audio_MIN (live, samples); |
61 |
samples = decr; |
hw->rpos = (hw->rpos + decr) % hw->samples; |
62 |
rpos = hw->rpos; |
return decr; |
63 |
while (samples) { |
} |
|
int left_till_end_samples = hw->samples - rpos; |
|
|
int convert_samples = audio_MIN (samples, left_till_end_samples); |
|
64 |
|
|
65 |
src = advance (hw->mix_buf, rpos * sizeof (st_sample_t)); |
static int no_write (SWVoiceOut *sw, void *buf, int len) |
66 |
memset (src, 0, convert_samples * sizeof (st_sample_t)); |
{ |
67 |
|
return audio_pcm_sw_write (sw, buf, len); |
68 |
|
} |
69 |
|
|
70 |
rpos = (rpos + convert_samples) % hw->samples; |
static int no_init_out (HWVoiceOut *hw, int freq, |
71 |
samples -= convert_samples; |
int nchannels, audfmt_e fmt) |
72 |
} |
{ |
73 |
|
audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); |
74 |
|
hw->bufsize = 4096; |
75 |
|
return 0; |
76 |
|
} |
77 |
|
|
78 |
pcm_hw_dec_live (hw, decr); |
static void no_fini_out (HWVoiceOut *hw) |
79 |
hw->rpos = rpos; |
{ |
80 |
|
(void) hw; |
81 |
} |
} |
82 |
|
|
83 |
static int no_hw_write (SWVoice *sw, void *buf, int len) |
static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) |
84 |
{ |
{ |
85 |
return pcm_hw_write (sw, buf, len); |
(void) hw; |
86 |
|
(void) cmd; |
87 |
|
return 0; |
88 |
} |
} |
89 |
|
|
90 |
static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) |
static int no_init_in (HWVoiceIn *hw, int freq, |
91 |
|
int nchannels, audfmt_e fmt) |
92 |
{ |
{ |
93 |
hw->freq = freq; |
audio_pcm_init_info (&hw->info, freq, nchannels, fmt, 0); |
|
hw->nchannels = nchannels; |
|
|
hw->fmt = fmt; |
|
94 |
hw->bufsize = 4096; |
hw->bufsize = 4096; |
95 |
return 0; |
return 0; |
96 |
} |
} |
97 |
|
|
98 |
static void no_hw_fini (HWVoice *hw) |
static void no_fini_in (HWVoiceIn *hw) |
99 |
{ |
{ |
100 |
(void) hw; |
(void) hw; |
101 |
} |
} |
102 |
|
|
103 |
static int no_hw_ctl (HWVoice *hw, int cmd, ...) |
static int no_run_in (HWVoiceIn *hw) |
104 |
|
{ |
105 |
|
NoVoiceIn *no = (NoVoiceIn *) hw; |
106 |
|
int64_t now = qemu_get_clock (vm_clock); |
107 |
|
int64_t ticks = now - no->old_ticks; |
108 |
|
int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; |
109 |
|
int live = audio_pcm_hw_get_live_in (hw); |
110 |
|
int dead = hw->samples - live; |
111 |
|
int samples; |
112 |
|
|
113 |
|
bytes = audio_MIN (bytes, INT_MAX); |
114 |
|
samples = bytes >> hw->info.shift; |
115 |
|
samples = audio_MIN (samples, dead); |
116 |
|
|
117 |
|
return samples; |
118 |
|
} |
119 |
|
|
120 |
|
static int no_read (SWVoiceIn *sw, void *buf, int size) |
121 |
|
{ |
122 |
|
int samples = size >> sw->info.shift; |
123 |
|
int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; |
124 |
|
int to_clear = audio_MIN (samples, total); |
125 |
|
audio_pcm_info_clear_buf (&sw->info, buf, to_clear); |
126 |
|
return to_clear; |
127 |
|
} |
128 |
|
|
129 |
|
static int no_ctl_in (HWVoiceIn *hw, int cmd, ...) |
130 |
{ |
{ |
131 |
(void) hw; |
(void) hw; |
132 |
(void) cmd; |
(void) cmd; |
140 |
|
|
141 |
static void no_audio_fini (void *opaque) |
static void no_audio_fini (void *opaque) |
142 |
{ |
{ |
143 |
|
(void) opaque; |
144 |
} |
} |
145 |
|
|
146 |
struct pcm_ops no_pcm_ops = { |
static struct audio_pcm_ops no_pcm_ops = { |
147 |
no_hw_init, |
no_init_out, |
148 |
no_hw_fini, |
no_fini_out, |
149 |
no_hw_run, |
no_run_out, |
150 |
no_hw_write, |
no_write, |
151 |
no_hw_ctl |
no_ctl_out, |
152 |
|
|
153 |
|
no_init_in, |
154 |
|
no_fini_in, |
155 |
|
no_run_in, |
156 |
|
no_read, |
157 |
|
no_ctl_in |
158 |
}; |
}; |
159 |
|
|
160 |
struct audio_output_driver no_output_driver = { |
struct audio_driver no_audio_driver = { |
161 |
"none", |
INIT_FIELD (name = ) "none", |
162 |
no_audio_init, |
INIT_FIELD (descr = ) "Timer based audio emulation", |
163 |
no_audio_fini, |
INIT_FIELD (options = ) NULL, |
164 |
&no_pcm_ops, |
INIT_FIELD (init = ) no_audio_init, |
165 |
1, |
INIT_FIELD (fini = ) no_audio_fini, |
166 |
1, |
INIT_FIELD (pcm_ops = ) &no_pcm_ops, |
167 |
sizeof (NoVoice) |
INIT_FIELD (can_be_default = ) 1, |
168 |
|
INIT_FIELD (max_voices_out = ) INT_MAX, |
169 |
|
INIT_FIELD (max_voices_in = ) INT_MAX, |
170 |
|
INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut), |
171 |
|
INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn) |
172 |
}; |
}; |