vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / opensound / OpenSoundAddOn.cpp
blob4c2cb5b8e4d10e321084d0ab0c6f88fa5be65943
1 /*
2 * OpenSound media addon for BeOS and Haiku
4 * Copyright (c) 2007, François Revol (revol@free.fr)
5 * Distributed under the terms of the MIT License.
6 *
7 * Based on MultiAudio media addon
8 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
9 */
10 #include "OpenSoundAddOn.h"
12 #include <MediaDefs.h>
13 #include <MediaAddOn.h>
14 #include <Errors.h>
15 #include <Node.h>
16 #include <Mime.h>
17 #include <StorageDefs.h>
18 #include <Path.h>
19 #include <Directory.h>
20 #include <Entry.h>
21 #include <FindDirectory.h>
22 #include <Debug.h>
23 #include <errno.h>
25 #include "OpenSoundNode.h"
26 #include "OpenSoundDevice.h"
27 #include "OpenSoundDeviceEngine.h"
29 #include <limits.h>
30 #include <stdio.h>
31 #include <string.h>
33 #include "debug.h"
35 #define MULTI_SAVE
38 // instantiation function
39 extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image) {
40 CALLED();
41 return new OpenSoundAddOn(image);
44 // -------------------------------------------------------- //
45 // ctor/dtor
46 // -------------------------------------------------------- //
48 OpenSoundAddOn::~OpenSoundAddOn()
50 CALLED();
52 void *device = NULL;
53 for (int32 i = 0; (device = fDevices.ItemAt(i)); i++)
54 delete (OpenSoundDevice *)device;
56 SaveSettings();
59 OpenSoundAddOn::OpenSoundAddOn(image_id image) :
60 BMediaAddOn(image),
61 fDevices()
63 CALLED();
64 fInitCheckStatus = B_NO_INIT;
66 /* unix paths */
67 if (RecursiveScan("/dev/oss/") != B_OK)
68 return;
70 if (RecursiveScan("/dev/audio/oss/") != B_OK)
71 return;
74 LoadSettings();
76 fInitCheckStatus = B_OK;
79 // -------------------------------------------------------- //
80 // BMediaAddOn impl
81 // -------------------------------------------------------- //
83 status_t OpenSoundAddOn::InitCheck(
84 const char ** out_failure_text)
86 CALLED();
87 return B_OK;
90 int32 OpenSoundAddOn::CountFlavors()
92 CALLED();
93 PRINT(("%" B_PRId32 " flavours\n", fDevices.CountItems()));
94 return fDevices.CountItems();
97 status_t OpenSoundAddOn::GetFlavorAt(
98 int32 n,
99 const flavor_info ** out_info)
101 CALLED();
102 if (n < 0 || n > fDevices.CountItems() - 1) {
103 fprintf(stderr, "<- B_BAD_INDEX\n");
104 return B_BAD_INDEX;
107 OpenSoundDevice *device = (OpenSoundDevice *) fDevices.ItemAt(n);
109 flavor_info * infos = new flavor_info[1];
110 OpenSoundNode::GetFlavor(&infos[0], n);
111 infos[0].name = device->fCardInfo.longname;
112 (*out_info) = infos;
113 return B_OK;
116 BMediaNode * OpenSoundAddOn::InstantiateNodeFor(
117 const flavor_info * info,
118 BMessage * config,
119 status_t * out_error)
121 CALLED();
123 OpenSoundDevice *device = (OpenSoundDevice*)fDevices.ItemAt(
124 info->internal_id);
125 if (device == NULL) {
126 *out_error = B_ERROR;
127 return NULL;
130 #ifdef MULTI_SAVE
131 if (fSettings.FindMessage(device->fCardInfo.longname, config) == B_OK) {
132 fSettings.RemoveData(device->fCardInfo.longname);
134 #endif
136 OpenSoundNode * node =
137 new OpenSoundNode(this,
138 device->fCardInfo.longname,
139 device,
140 info->internal_id,
141 config);
142 if (node == 0) {
143 *out_error = B_NO_MEMORY;
144 fprintf(stderr, "<- B_NO_MEMORY\n");
145 } else {
146 *out_error = node->InitCheck();
148 return node;
151 status_t
152 OpenSoundAddOn::GetConfigurationFor(BMediaNode * your_node, BMessage * into_message)
154 CALLED();
155 #ifdef MULTI_SAVE
157 into_message = new BMessage();
158 OpenSoundNode * node = dynamic_cast<OpenSoundNode*>(your_node);
159 if (node == 0) {
160 fprintf(stderr, "<- B_BAD_TYPE\n");
161 return B_BAD_TYPE;
163 if (node->GetConfigurationFor(into_message) == B_OK) {
164 fSettings.AddMessage(your_node->Name(), into_message);
166 return B_OK;
168 #endif
169 // currently never called by the media kit. Seems it is not implemented.
170 OpenSoundNode * node = dynamic_cast<OpenSoundNode*>(your_node);
171 if (node == 0) {
172 fprintf(stderr, "<- B_BAD_TYPE\n");
173 return B_BAD_TYPE;
175 return node->GetConfigurationFor(into_message);
179 bool OpenSoundAddOn::WantsAutoStart()
181 CALLED();
182 return false;
185 status_t OpenSoundAddOn::AutoStart(
186 int in_count,
187 BMediaNode ** out_node,
188 int32 * out_internal_id,
189 bool * out_has_more)
191 CALLED();
192 return B_OK;
195 status_t
196 OpenSoundAddOn::RecursiveScan(const char* rootPath, BEntry *rootEntry)
198 status_t err;
199 int mixer;
200 oss_sysinfo sysinfo;
201 oss_card_info cardinfo;
202 int card, i, j;
203 BList devs;
205 CALLED();
207 // make sure directories are scanned in this order
208 BDirectory("/dev/audio/hmulti");
209 BDirectory("/dev/audio/old");
210 // OSS last, to give precedence to native drivers.
211 // If other addons are loaded first it's ok as well.
212 // Also, we must open it to make sure oss_loader is here,
213 // else we don't get /dev/sndstat since we don't have a symlink in dev/.
214 BDirectory("/dev/oss");
216 mixer = open(OSS_MIXER_DEV, O_RDWR);
217 if (mixer < 0) {
218 // try to rescan
219 // only works in BeOS
220 BFile fDevFS("/dev/.", B_WRITE_ONLY);
221 const char *drv = "oss_loader";
222 fDevFS.Write(drv, strlen(drv));
223 mixer = open(OSS_MIXER_DEV, O_RDWR);
224 if (mixer < 0) {
225 err = errno;
226 goto err0;
230 if (ioctl(mixer, SNDCTL_SYSINFO, &sysinfo) < 0) {
231 err = errno;
232 goto err1;
235 PRINT(("OSS: %s %s (0x%08X)\n", sysinfo.product, sysinfo.version, sysinfo.versionnum));
236 PRINT(("OSS: %d audio cards, %d audio devs, %d audio engines, %d midi, %d mixers\n", sysinfo.numcards, sysinfo.numaudios, sysinfo.numaudioengines, sysinfo.nummidis, sysinfo.nummixers));
238 /* construct an empty SoundDevice per card */
240 for (card = 0; card < sysinfo.numcards; card++) {
241 cardinfo.card = card;
242 if (ioctl(mixer, SNDCTL_CARDINFO, &cardinfo) < 0) {
243 err = errno;
244 goto err1;
246 OpenSoundDevice *device = new OpenSoundDevice(&cardinfo);
247 if (device)
248 devs.AddItem(device);
249 else {
250 err = ENOMEM;
251 goto err1;
255 /* Add its audio engines to it */
257 for (i = 0; i < sysinfo.numaudioengines; i++) {
258 oss_audioinfo audioinfo;
259 audioinfo.dev = i;
260 if (ioctl(mixer, SNDCTL_ENGINEINFO, &audioinfo, sizeof(oss_audioinfo)) < 0) {
261 err = errno;
262 goto err1;
264 PRINT(("OSS: engine[%d]: card=%d, port=%d, legacy=%d, next_play=%d, next_rec=%d\n", i, audioinfo.card_number, audioinfo.port_number, audioinfo.legacy_device, audioinfo.next_play_engine, audioinfo.next_rec_engine));
265 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(audioinfo.card_number));
266 if (device)
267 device->AddEngine(&audioinfo);
270 /* Add its mixers to it */
272 for (i = 0; i < sysinfo.nummixers; i++) {
273 oss_mixerinfo mixerinfo;
274 mixerinfo.dev = i;
275 if (ioctl(mixer, SNDCTL_MIXERINFO, &mixerinfo) < 0) {
276 err = errno;
277 goto err1;
279 PRINT(("OSS: mixer[%d]: card=%d\n", i, mixerinfo.card_number));
280 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(mixerinfo.card_number));
281 if (device)
282 device->AddMixer(&mixerinfo);
285 /* resolve engine chains of shadow engines */
287 for (card = 0; card < sysinfo.numcards; card++) {
288 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(card));
289 if (!device)
290 continue;
291 for (i = 0; i < device->CountEngines(); i++) {
292 OpenSoundDeviceEngine *engine = device->EngineAt(i);
293 if (engine) {
294 if (engine->Info()->next_play_engine) {
295 for (j = 0; j < device->CountEngines(); j++) {
296 OpenSoundDeviceEngine *next = device->EngineAt(j);
297 if (!next || (engine == next))
298 continue;
299 if (next->Info()->dev == engine->Info()->next_play_engine) {
300 PRINT(("OSS: engine[%d].next_play = engine[%d]\n", i, j));
301 engine->fNextPlay = next;
302 break;
306 if (engine->Info()->next_rec_engine) {
307 for (j = 0; j < device->CountEngines(); j++) {
308 OpenSoundDeviceEngine *next = device->EngineAt(j);
309 if (!next || (engine == next))
310 continue;
311 if (next->Info()->dev == engine->Info()->next_rec_engine) {
312 PRINT(("OSS: engine[%d].next_rec = engine[%d]\n", i, j));
313 engine->fNextRec = next;
314 break;
322 /* copy correctly initialized devs to fDevices */
324 for (card = 0; card < sysinfo.numcards; card++) {
325 OpenSoundDevice *device = (OpenSoundDevice *)(devs.ItemAt(card));
326 if (device) {
327 if (card == 0) { /* skip the "oss0" pseudo card device */
328 delete device;
329 continue;
331 if ((device->InitDriver() == B_OK) && (device->InitCheck() == B_OK))
332 fDevices.AddItem(device);
333 else
334 delete device;
337 if (fDevices.CountItems())
338 err = B_OK;
339 else
340 err = ENOENT;
341 err1:
342 close(mixer);
343 err0:
344 return err;
346 #if MA
347 BDirectory root;
348 if (rootEntry != NULL)
349 root.SetTo(rootEntry);
350 else if (rootPath != NULL) {
351 root.SetTo(rootPath);
352 } else {
353 PRINT(("Error in OpenSoundAddOn::RecursiveScan null params\n"));
354 return B_ERROR;
357 BEntry entry;
359 while (root.GetNextEntry(&entry) > B_ERROR) {
361 if (entry.IsDirectory()) {
362 BPath path;
363 entry.GetPath(&path);
364 OpenSoundDevice *device = new OpenSoundDevice(path.Path() + strlen(rootPath), path.Path());
365 if (device) {
366 if (device->InitCheck() == B_OK)
367 fDevices.AddItem(device);
368 else
369 delete device;
374 return B_OK;
375 #endif
379 void
380 OpenSoundAddOn::SaveSettings(void)
382 CALLED();
383 BPath path;
384 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
385 path.Append(SETTINGS_FILE);
386 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
387 if (file.InitCheck() == B_OK)
388 fSettings.Flatten(&file);
393 void
394 OpenSoundAddOn::LoadSettings(void)
396 CALLED();
397 fSettings.MakeEmpty();
399 BPath path;
400 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
401 path.Append(SETTINGS_FILE);
402 BFile file(path.Path(), B_READ_ONLY);
403 if ((file.InitCheck() == B_OK) && (fSettings.Unflatten(&file) == B_OK))
405 PRINT_OBJECT(fSettings);
406 } else {
407 PRINT(("Error unflattening settings file %s\n", path.Path()));
413 void
414 OpenSoundAddOn::RegisterMediaFormats(void)
416 CALLED();
417 // register non-raw audio formats to the Media Kit
418 #ifdef ENABLE_NON_RAW_SUPPORT
419 OpenSoundDevice::register_media_formats();
420 #endif