2 * Copyright (c) 2002-2007, Jerome Duval (jerome.duval@free.fr)
3 * Copyright (c) 2007, François Revol (revol@free.fr)
4 * Distributed under the terms of the MIT License.
7 #include "OpenSoundDevice.h"
8 #include "OpenSoundDeviceEngine.h"
9 #include "OpenSoundDeviceMixer.h"
11 #include "driver_io.h"
12 #include <MediaDefs.h>
17 const int gSupportedFormats
[] = {
19 #ifdef ENABLE_NON_RAW_SUPPORT
28 #endif /*ENABLE_NON_RAW_SUPPORT*/
32 const char* gSupportedFormatsNames
[] = {
33 "raw", //AFMT_SUPPORTED_PCM,
34 "µ-law", //AFMT_MU_LAW,
35 "a-law", //AFMT_A_LAW,
36 "IMA4 ADPCM", //AFMT_IMA_ADPCM,
37 "MPEG layer 2", //AFMT_MPEG,
39 "Vorbis", //AFMT_VORBIS,
40 "Raw S/PDIF", //AFMT_SPDIF_RAW,
41 "Packed 24bit", //AFMT_S24_PACKED,*/
48 float OpenSoundDevice::convert_oss_rate_to_media_rate(int rate
)
54 int OpenSoundDevice::convert_media_rate_to_oss_rate(float rate
)
60 uint32
OpenSoundDevice::convert_oss_format_to_media_format(int fmt
)
63 return media_raw_audio_format::B_AUDIO_FLOAT
;
64 if (fmt
& AFMT_S32_LE
||
68 return media_raw_audio_format::B_AUDIO_INT
;
69 if (fmt
& AFMT_S16_LE
||
70 fmt
& AFMT_S16_BE
) /* U16 unsupported */
71 return media_raw_audio_format::B_AUDIO_SHORT
;
73 return media_raw_audio_format::B_AUDIO_CHAR
;
75 return media_raw_audio_format::B_AUDIO_UCHAR
;
80 int OpenSoundDevice::convert_oss_format_to_endian(int fmt
)
83 return B_MEDIA_HOST_ENDIAN
;
84 if (fmt
& AFMT_S32_LE
||
88 fmt
& AFMT_S24_PACKED
)
89 return B_MEDIA_LITTLE_ENDIAN
;
90 if (fmt
& AFMT_S32_BE
||
94 return B_MEDIA_BIG_ENDIAN
;
97 return B_MEDIA_HOST_ENDIAN
;
98 return B_MEDIA_HOST_ENDIAN
;
101 int16
OpenSoundDevice::convert_oss_format_to_valid_bits(int fmt
)
103 if (fmt
& AFMT_S32_NE
)
105 if (fmt
& AFMT_S24_NE
)
107 if (fmt
& AFMT_S32_OE
)
109 if (fmt
& AFMT_S24_OE
)
111 if (fmt
& AFMT_S24_PACKED
)
113 if (fmt
& AFMT_SPDIF_RAW
)
119 int OpenSoundDevice::convert_media_format_to_oss_format(uint32 fmt
)
122 case media_raw_audio_format::B_AUDIO_FLOAT
:
124 case media_raw_audio_format::B_AUDIO_INT
:
126 case media_raw_audio_format::B_AUDIO_SHORT
:
128 case media_raw_audio_format::B_AUDIO_CHAR
:
130 case media_raw_audio_format::B_AUDIO_UCHAR
:
138 int OpenSoundDevice::select_oss_rate(const oss_audioinfo
*info
, int rate
)
140 if (info
->caps
& PCM_CAP_FREERATE
) {
141 // if not wildcard and matches, return the hint
142 if (rate
&& rate
>= info
->min_rate
&& rate
<= info
->max_rate
)
144 // else use max available
145 return info
->max_rate
;
148 for (uint32 i
= 0; i
< info
->nrates
; i
++) {
149 if ((int32
)info
->rates
[i
] < info
->min_rate
150 || (int32
)info
->rates
[i
] > info
->max_rate
)
152 // if the hint matches
153 if (rate
&& rate
== (int32
)info
->rates
[i
])
155 if (info
->rates
[i
] > max_rate
)
156 max_rate
= info
->rates
[i
];
163 int OpenSoundDevice::select_oss_format(int fmt
)
165 //highest format, Native Endian first
166 if (fmt
& AFMT_FLOAT
) {
168 } else if (fmt
& AFMT_S32_NE
) {
170 } else if (fmt
& AFMT_S24_NE
) {
172 } else if (fmt
& AFMT_S16_NE
) {
174 } else if (fmt
& AFMT_S32_OE
) {
176 } else if (fmt
& AFMT_S24_OE
) {
178 } else if (fmt
& AFMT_S16_OE
) {
180 } else if (fmt
& AFMT_S8
) {
182 } else if (fmt
& AFMT_U8
) {
188 status_t
OpenSoundDevice::get_media_format_description_for(int fmt
, media_format_description
*desc
, int count
)
191 for (i
= 0; i
< count
; i
++)
192 memset(&desc
[i
], 0, sizeof(media_format_description
));
195 if (fmt
& AFMT_SUPPORTED_PCM
) {
196 desc
[0].family
= B_BEOS_FORMAT_FAMILY
;
197 desc
[0].u
.beos
.format
= 1;
202 desc
[0].family
= B_MISC_FORMAT_FAMILY
;
203 desc
[0].u
.misc
.file_format
= '.snd';
204 desc
[0].u
.misc
.codec
= 'ulaw';
207 desc
[1].family
= B_WAV_FORMAT_FAMILY
;
208 desc
[1].u
.wav
.codec
= 0x07;
212 desc
[1].family
= B_QUICKTIME_FORMAT_FAMILY
;
213 desc
[1].u
.quicktime
.codec
= 'ulaw';
214 desc
[1].u
.quicktime
.vendor
= 0;
217 desc
[0].family
= B_MISC_FORMAT_FAMILY
;
218 desc
[0].u
.misc
.file_format
= '.snd';
219 desc
[0].u
.misc
.codec
= 'alaw';
223 desc
[0].family
= B_BEOS_FORMAT_FAMILY
;
224 desc
[0].u
.beos
.format
= 'ima4';
226 case AFMT_MPEG
: /* layer 2 */
227 desc
[0].family
= B_MPEG_FORMAT_FAMILY
;
228 desc
[0].u
.mpeg
.id
= 0x102;
231 desc
[1].family
= B_WAV_FORMAT_FAMILY
;
232 desc
[1].u
.wav
.codec
= 0x50;
235 desc
[1].family
= B_AVI_FORMAT_FAMILY
;
236 desc
[1].u
.avi
.codec
= 0x65610050;
239 desc
[0].family
= B_WAV_FORMAT_FAMILY
;
240 desc
[0].u
.wav
.codec
= 0x2000;
243 desc
[1].family
= B_AVI_FORMAT_FAMILY
;
244 desc
[1].u
.avi
.codec
= 0x65612000;
248 desc
[0].family
= B_MISC_FORMAT_FAMILY
;
249 desc
[0].u
.misc
.file_format
= 'OSS4';
250 desc
[0].u
.misc
.codec
= 'VORB';
254 desc
[0].family
= B_MISC_FORMAT_FAMILY
;
255 desc
[0].u
.misc
.file_format
= 'OSS4';
256 desc
[0].u
.misc
.codec
= 'PDIF';
258 case AFMT_S24_PACKED
:
260 desc
[0].family
= B_MISC_FORMAT_FAMILY
;
261 desc
[0].u
.misc
.file_format
= 'OSS4';
262 desc
[0].u
.misc
.codec
= 'S24P';
271 status_t
OpenSoundDevice::register_media_formats()
275 BMediaFormats formats
;
276 if (formats
.InitCheck() < B_OK
)
277 return formats
.InitCheck();
279 for (i
= 0; gSupportedFormats
[i
]; i
++) {
280 media_format_description desc
[10];
281 err
= count
= get_media_format_description_for(gSupportedFormats
[i
], desc
, 10);
284 if (gSupportedFormats
[i
] & AFMT_SUPPORTED_PCM
) {
285 format
.type
= B_MEDIA_RAW_AUDIO
;
286 format
.u
.raw_audio
= media_multi_audio_format::wildcard
;
288 format
.type
= B_MEDIA_ENCODED_AUDIO
;
289 format
.u
.encoded_audio
= media_encoded_audio_format::wildcard
;
291 err
= formats
.MakeFormatFor(desc
, count
, &format
);
292 PRINT(("OpenSoundDevice::register_media_formats: MakeFormatFor: %s\n", strerror(err
)));
298 status_t
OpenSoundDevice::get_media_format_for(int fmt
, media_format
&format
)
301 BMediaFormats formats
;
302 if (formats
.InitCheck() < B_OK
)
303 return formats
.InitCheck();
304 /* shortcut for raw */
305 if (fmt
& AFMT_SUPPORTED_PCM
) {
306 format
= media_format();
307 format
.type
= B_MEDIA_RAW_AUDIO
;
308 format
.u
.raw_audio
= media_raw_audio_format::wildcard
;
311 media_format_description desc
;
312 err
= get_media_format_description_for(fmt
, &desc
);
315 err
= formats
.GetFormatFor(desc
, &format
);
320 OpenSoundDevice::~OpenSoundDevice()
323 OpenSoundDeviceEngine
*engine
;
324 OpenSoundDeviceMixer
*mixer
;
325 while ((engine
= EngineAt(0))) {
327 fEngines
.RemoveItems(0, 1);
329 while ((mixer
= MixerAt(0))) {
331 fMixers
.RemoveItems(0, 1);
335 OpenSoundDevice::OpenSoundDevice(oss_card_info
*cardinfo
)
336 : fLocker("OpenSoundDevice")
339 fInitCheckStatus
= B_NO_INIT
;
340 memcpy(&fCardInfo
, cardinfo
, sizeof(oss_card_info
));
341 memset(&fFragments
, 0, sizeof(fFragments
));
343 strcpy(fDevice_name
, name
);
344 strcpy(fDevice_path
, path
);
346 PRINT(("name : %s, path : %s\n", fDevice_name
, fDevice_path
));
348 if (InitDriver() != B_OK
)
351 fInitCheckStatus
= B_OK
;
356 status_t
OpenSoundDevice::InitCheck(void) const
359 return fInitCheckStatus
;
363 status_t
OpenSoundDevice::InitDriver()
367 PRINT(("OpenSoundDevice::InitDriver: %" B_PRId32
" engines, %" B_PRId32
368 " mixers\n", CountEngines(), CountMixers()));
374 fInitCheckStatus
= B_OK
;
381 OpenSoundDevice::AddEngine(oss_audioinfo
*info
)
384 /* discard shadow/hidden engines (!?) */
387 if (info->caps & PCM_CAP_SHADOW)
389 if (info->caps & PCM_CAP_HIDDEN)
392 OpenSoundDeviceEngine
*engine
= new OpenSoundDeviceEngine(info
);
395 err
= engine
->InitCheck();
400 fEngines
.AddItem(engine
);
406 OpenSoundDevice::AddMixer(oss_mixerinfo
*info
)
410 OpenSoundDeviceMixer
*mixer
= new OpenSoundDeviceMixer(info
);
413 err
= mixer
->InitCheck();
418 fMixers
.AddItem(mixer
);
424 OpenSoundDevice::CountEngines()
426 return fEngines
.CountItems();
431 OpenSoundDevice::CountMixers()
433 return fMixers
.CountItems();
437 OpenSoundDeviceEngine
*
438 OpenSoundDevice::EngineAt(int32 i
)
440 return (OpenSoundDeviceEngine
*)(fEngines
.ItemAt(i
));
444 OpenSoundDeviceMixer
*
445 OpenSoundDevice::MixerAt(int32 i
)
447 return (OpenSoundDeviceMixer
*)(fMixers
.ItemAt(i
));
450 OpenSoundDeviceEngine
*
451 OpenSoundDevice::NextFreeEngineAt(int32 i
, bool rec
)
453 // find the first free engine in the rec or play chain
454 OpenSoundDeviceEngine
*engine
= EngineAt(i
);
455 while (engine
&& engine
->InUse()) {
456 engine
= rec
? (engine
->NextRec()) : (engine
->NextPlay());