drc: avoid excessive recursion in hle mode
[pcsx_rearmed.git] / plugins / dfsound / oss.c
1 /***************************************************************************
2                             oss.c  -  description
3                              -------------------
4     begin                : Wed May 15 2002
5     copyright            : (C) 2002 by Pete Bernert
6     email                : BlackDove@addcom.de
7  ***************************************************************************/
8 /***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version. See also the license.txt file for *
14  *   additional informations.                                              *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <unistd.h>
25 #include <sys/soundcard.h>
26 #include "out.h"
27
28 ////////////////////////////////////////////////////////////////////////
29 // oss globals
30 ////////////////////////////////////////////////////////////////////////
31
32 #define OSS_MODE_STEREO     1
33 #define OSS_MODE_MONO       0
34
35 #define OSS_SPEED_44100     44100
36
37 #define FRAGMENT_SHIFT 12
38 #define FRAGMENT_SIZE  (1 << FRAGMENT_SHIFT)
39
40 static int oss_audio_fd = -1;
41 extern int errno;
42
43 ////////////////////////////////////////////////////////////////////////
44 // SETUP SOUND
45 ////////////////////////////////////////////////////////////////////////
46
47 static int oss_init(void)
48 {
49  int pspeed=44100;
50  int pstereo;
51  int format;
52  int myfrag;
53  int oss_speed, oss_stereo;
54
55  pstereo = OSS_MODE_STEREO;
56  oss_speed = pspeed;
57  oss_stereo = pstereo;
58
59  if((oss_audio_fd=open("/dev/dsp",O_WRONLY,0))==-1)
60   {
61    printf("OSS device not available\n");
62    return -1;
63   }
64
65  if(ioctl(oss_audio_fd,SNDCTL_DSP_RESET,0)==-1)
66   {
67    printf("Sound reset failed\n");
68    return -1;
69   }
70
71  // we use 64 fragments with 1024 bytes each
72  // rearmed: now using 10*4096 for better latency
73
74  myfrag = (10<<16) | FRAGMENT_SHIFT;
75
76  if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFRAGMENT,&myfrag)==-1)
77   {
78    printf("Sound set fragment failed!\n");
79    return -1;
80   }
81
82  format = AFMT_S16_NE;
83
84  if(ioctl(oss_audio_fd,SNDCTL_DSP_SETFMT,&format) == -1)
85   {
86    printf("Sound format not supported!\n");
87    return -1;
88   }
89
90  if(format!=AFMT_S16_NE)
91   {
92    printf("Sound format not supported!\n");
93    return -1;
94   }
95
96  if(ioctl(oss_audio_fd,SNDCTL_DSP_STEREO,&oss_stereo)==-1 || !oss_stereo)
97   {
98    printf("Stereo mode not supported!\n");
99    return -1;
100   }
101
102  if(ioctl(oss_audio_fd,SNDCTL_DSP_SPEED,&oss_speed)==-1)
103   {
104    printf("Sound frequency not supported\n");
105    return -1;
106   }
107
108  if(oss_speed!=pspeed)
109   {
110    printf("Sound frequency not supported\n");
111    return -1;
112   }
113
114  return 0;
115 }
116
117 ////////////////////////////////////////////////////////////////////////
118 // REMOVE SOUND
119 ////////////////////////////////////////////////////////////////////////
120
121 static void oss_finish(void)
122 {
123  if(oss_audio_fd != -1 )
124   {
125    close(oss_audio_fd);
126    oss_audio_fd = -1;
127   }
128 }
129
130 ////////////////////////////////////////////////////////////////////////
131 // GET BUFFERED STATUS
132 ////////////////////////////////////////////////////////////////////////
133
134 static int oss_busy(void)
135 {
136  audio_buf_info info;
137  unsigned long l;
138
139  if(oss_audio_fd == -1) return 1;
140  if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==-1)
141   l=0;
142  else
143   {
144    if(info.fragments<(info.fragstotal>>1))             // can we write in at least the half of fragments?
145         l=1;                                           // -> no? wait
146    else l=0;                                           // -> else go on
147   }
148
149  return l;
150 }
151
152 ////////////////////////////////////////////////////////////////////////
153 // FEED SOUND DATA
154 ////////////////////////////////////////////////////////////////////////
155
156 static void oss_feed(void *buf, int bytes)
157 {
158  audio_buf_info info;
159  char sbuf[4096];
160
161  if(oss_audio_fd == -1) return;
162  if(ioctl(oss_audio_fd,SNDCTL_DSP_GETOSPACE,&info)==0)
163   {
164    // for fast forward
165    if(bytes > info.fragments * FRAGMENT_SIZE)
166     bytes = info.fragments * FRAGMENT_SIZE;
167    if(bytes == 0)
168     return;
169
170    if(info.fragments==info.fragstotal)
171     {
172      memset(sbuf, 0, sizeof(sbuf));
173      write(oss_audio_fd, sbuf, sizeof(sbuf));
174      write(oss_audio_fd, sbuf, sizeof(sbuf));
175      write(oss_audio_fd, sbuf, sizeof(sbuf));
176     }
177   }
178
179  write(oss_audio_fd, buf, bytes);
180 }
181
182 void out_register_oss(struct out_driver *drv)
183 {
184         drv->name = "oss";
185         drv->init = oss_init;
186         drv->finish = oss_finish;
187         drv->busy = oss_busy;
188         drv->feed = oss_feed;
189 }