pandora: tripplebuffer fbdev out, refactoring
[libpicofe.git] / linux / sndout_oss.c
CommitLineData
b3972d82 1/* sound output via OSS */
2#include <stdio.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <fcntl.h>
6#include <sys/ioctl.h>
7#include <sys/soundcard.h>
8#include <unistd.h>
9
10#include "sndout_oss.h"
11
12static int sounddev = -1, mixerdev = -1;
dd59a74b 13static int can_write_safe;
14
b3972d82 15
16int sndout_oss_init(void)
17{
18 if (mixerdev >= 0) close(mixerdev);
19 mixerdev = open("/dev/mixer", O_RDWR);
20 if (mixerdev == -1)
21 {
22 perror("open(\"/dev/mixer\")");
23 }
24
25 return 0;
26}
27
b188c2b6 28void sndout_oss_stop(void)
29{
30 if (sounddev < 0)
31 return;
32
33 ioctl(sounddev, SOUND_PCM_SYNC, 0);
34 close(sounddev);
35 sounddev = -1;
36}
37
dd59a74b 38int sndout_oss_start(int rate, int frame_samples, int stereo)
b3972d82 39{
dd59a74b 40 static int s_oldrate = 0, s_old_fsamples = 0, s_oldstereo = 0;
41 int frag, bsize, bits, ret;
b3972d82 42
b188c2b6 43 // GP2X: if no settings change, we don't need to do anything,
44 // since audio is never stopped there
45 if (sounddev >= 0 && rate == s_oldrate && s_old_fsamples == frame_samples && s_oldstereo == stereo)
b3972d82 46 return 0;
47
b188c2b6 48 sndout_oss_stop();
b3972d82 49 sounddev = open("/dev/dsp", O_WRONLY|O_ASYNC);
50 if (sounddev == -1)
51 {
52 perror("open(\"/dev/dsp\")");
5f7b5155 53 sounddev = open("/dev/dsp1", O_WRONLY|O_ASYNC);
54 if (sounddev == -1) {
55 perror("open(\"/dev/dsp1\")");
56 return -1;
57 }
b3972d82 58 }
59
114dfebd 60 // calculate buffer size. We want to fit 1 frame worth of sound data.
dd59a74b 61 // Also ignore mono because both GP2X and Wiz mixes mono to stereo anyway.
62 bsize = frame_samples << 2;
63
64 for (frag = 0; bsize; bsize >>= 1, frag++)
65 ;
b3972d82 66
dd59a74b 67 frag |= 16 << 16; // fragment count
68 ret = ioctl(sounddev, SNDCTL_DSP_SETFRAGMENT, &frag);
69 if (ret < 0)
70 perror("SNDCTL_DSP_SETFRAGMENT failed");
71
72 bits = 16;
73 ret = ioctl(sounddev, SNDCTL_DSP_STEREO, &stereo);
74 if (ret == 0)
75 ret = ioctl(sounddev, SNDCTL_DSP_SETFMT, &bits);
76 if (ret == 0)
77 ret = ioctl(sounddev, SNDCTL_DSP_SPEED, &rate);
78 if (ret < 0)
79 perror("failed to set audio format");
80
b188c2b6 81#ifdef __GP2X__
dd59a74b 82 // not sure if this is still needed (avoiding driver bugs?)
b3972d82 83 usleep(192*1024);
b188c2b6 84#endif
b3972d82 85
dd59a74b 86 printf("sndout_oss_start: %d/%dbit/%s, %d buffers of %i bytes\n",
87 rate, bits, stereo ? "stereo" : "mono", frag >> 16, 1 << (frag & 0xffff));
b3972d82 88
dd59a74b 89 s_oldrate = rate; s_old_fsamples = frame_samples; s_oldstereo = stereo;
90 can_write_safe = 0;
b3972d82 91 return 0;
92}
93
b3972d82 94int sndout_oss_write(const void *buff, int len)
95{
96 return write(sounddev, buff, len);
97}
98
dd59a74b 99int sndout_oss_can_write(int bytes)
100{
101 audio_buf_info bi;
102 int ret;
103
104#ifdef __GP2X__
105 // note: SNDCTL_DSP_GETOSPACE crashes F100 kernel for some reason
106 // if called too early, so we work around here
107 if (can_write_safe++ < 8)
108 return 1;
109#endif
110 ret = ioctl(sounddev, SNDCTL_DSP_GETOSPACE, &bi);
111 if (ret < 0)
112 return 1;
113
114 // have enough bytes to write + 4 extra frags
115 return bi.bytes - bi.fragsize * 4 >= bytes ? 1 : 0;
116}
b3972d82 117
118void sndout_oss_sync(void)
119{
120 ioctl(sounddev, SOUND_PCM_SYNC, 0);
121}
122
b3972d82 123void sndout_oss_setvol(int l, int r)
124{
125 if (mixerdev < 0) return;
126
127 l=l<0?0:l; l=l>255?255:l; r=r<0?0:r; r=r>255?255:r;
128 l<<=8; l|=r;
129 ioctl(mixerdev, SOUND_MIXER_WRITE_PCM, &l); /*SOUND_MIXER_WRITE_VOLUME*/
130}
131
b3972d82 132void sndout_oss_exit(void)
133{
134 if (sounddev >= 0) close(sounddev); sounddev = -1;
135 if (mixerdev >= 0) close(mixerdev); mixerdev = -1;
136}
137