rm unused preprocessor checks
[libpicofe.git] / linux / sndout_alsa.c
CommitLineData
32d23d03
GI
1/*
2 * (C) notaz, 2013
3 *
4 * This work is licensed under the terms of any of these licenses
5 * (at your option):
6 * - GNU GPL, version 2 or later.
7 * - GNU LGPL, version 2.1 or later.
8 * - MAME license.
9 * See the COPYING file in the top-level directory.
10 */
11
12#include <stdio.h>
13#include <alsa/asoundlib.h>
14#include <unistd.h>
15
16#include "sndout_alsa.h"
17
18static snd_pcm_t *handle;
19static snd_pcm_uframes_t buffer_size, period_size;
20static unsigned int channels;
21static void *silent_period;
22
23int sndout_alsa_init(void)
24{
25 int ret;
26
27 ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
28 if (ret != 0)
29 return -1;
30
31 return 0;
32}
33
34int sndout_alsa_start(int rate_, int stereo)
35{
36 snd_pcm_hw_params_t *hwparams = NULL;
37 unsigned int rate = rate_;
38 int samples, shift;
39 int ret;
40
41 samples = rate * 40 / 1000;
42 for (shift = 8; (1 << shift) < samples; shift++)
43 ;
44 period_size = 1 << shift;
45 buffer_size = 8 * period_size;
46
47 snd_pcm_hw_params_alloca(&hwparams);
48
49 ret = snd_pcm_hw_params_any(handle, hwparams);
50 ret |= snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
51 ret |= snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
52 ret |= snd_pcm_hw_params_set_channels(handle, hwparams, stereo ? 2 : 1);
53 ret |= snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0);
54 ret |= snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_size);
55 ret |= snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, NULL);
56
57 if (ret != 0) {
58 fprintf(stderr, "sndout_alsa: failed to set hwparams\n");
59 return -1;
60 }
61
62 ret = snd_pcm_hw_params(handle, hwparams);
63 if (ret != 0) {
64 fprintf(stderr, "sndout_alsa: failed to apply hwparams: %d\n",
65 ret);
66 return -1;
67 }
68
69 snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
70 snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL);
71 snd_pcm_hw_params_get_channels(hwparams, &channels);
72
73 silent_period = realloc(silent_period, period_size * 2 * channels);
74 if (silent_period != NULL)
75 memset(silent_period, 0, period_size * 2 * channels);
76
77 ret = snd_pcm_prepare(handle);
78 ret |= snd_pcm_start(handle);
79
80 if (ret != 0) {
81 fprintf(stderr, "sndout_alsa: failed to start pcm: %d\n",
82 ret);
83 return -1;
84 }
85
86 return 0;
87}
88
89void sndout_alsa_stop(void)
90{
91 // nothing?
92}
93
94void sndout_alsa_wait(void)
95{
96 snd_pcm_sframes_t left;
97
98 while (1)
99 {
100 left = snd_pcm_avail(handle);
101 if (left < 0 || left >= buffer_size / 2)
102 break;
103
104 usleep(4000);
105 }
106}
107
108int sndout_alsa_write_nb(const void *samples, int len)
109{
110 snd_pcm_sframes_t left;
111 int ret;
112
113 len /= 2;
114 if (channels == 2)
115 len /= 2;
116
117 left = snd_pcm_avail(handle);
118 if (left >= 0 && left < len)
119 return 0;
120
121 ret = snd_pcm_writei(handle, samples, len);
122 if (ret < 0) {
123 ret = snd_pcm_recover(handle, ret, 1);
124 if (ret != 0)
125 fprintf(stderr, "sndout_alsa snd_pcm_recover: %d\n", ret);
126
127 if (silent_period)
128 snd_pcm_writei(handle, silent_period, period_size);
129 snd_pcm_writei(handle, samples, len);
130 }
131
132 return len;
133}
134
135void sndout_alsa_exit(void)
136{
137 snd_pcm_close(handle);
138 handle = NULL;
139}