xref: /haiku/src/add-ons/media/media-add-ons/multi_audio/MultiAudioAddOn.cpp (revision 2f470aec1c92ce6917b8a903e343795dc77af41f)
1 /*
2  * Copyright (c) 2002, Jerome Duval (jerome.duval@free.fr)
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <MediaDefs.h>
7 #include <MediaAddOn.h>
8 #include <Errors.h>
9 #include <Node.h>
10 #include <Mime.h>
11 #include <StorageDefs.h>
12 #include <Path.h>
13 #include <Directory.h>
14 #include <Entry.h>
15 #include <FindDirectory.h>
16 
17 #include "MultiAudioNode.h"
18 #include "MultiAudioAddOn.h"
19 #include "MultiAudioDevice.h"
20 
21 #include <limits.h>
22 #include <stdio.h>
23 #include <string.h>
24 
25 #include "debug.h"
26 
27 #define MULTI_SAVE
28 
29 // instantiation function
30 extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image) {
31 	CALLED();
32 	return new MultiAudioAddOn(image);
33 }
34 
35 // -------------------------------------------------------- //
36 // ctor/dtor
37 // -------------------------------------------------------- //
38 
39 MultiAudioAddOn::~MultiAudioAddOn()
40 {
41 	CALLED();
42 
43 	void *device = NULL;
44 	for (int32 i = 0; (device = fDevices.ItemAt(i)); i++)
45 		delete (MultiAudioDevice *)device;
46 
47 	SaveSettings();
48 }
49 
50 MultiAudioAddOn::MultiAudioAddOn(image_id image) :
51 	BMediaAddOn(image),
52 	fDevices()
53 {
54 	CALLED();
55 	fInitCheckStatus = B_NO_INIT;
56 
57 	if (RecursiveScan("/dev/audio/hmulti/") != B_OK)
58 		return;
59 
60 	LoadSettings();
61 
62 	fInitCheckStatus = B_OK;
63 }
64 
65 // -------------------------------------------------------- //
66 // BMediaAddOn impl
67 // -------------------------------------------------------- //
68 
69 status_t MultiAudioAddOn::InitCheck(
70 	const char ** out_failure_text)
71 {
72 	CALLED();
73 	return B_OK;
74 }
75 
76 int32 MultiAudioAddOn::CountFlavors()
77 {
78 	CALLED();
79 	return fDevices.CountItems();
80 }
81 
82 status_t MultiAudioAddOn::GetFlavorAt(
83 	int32 n,
84 	const flavor_info ** out_info)
85 {
86 	CALLED();
87 	if (out_info == 0) {
88 		fprintf(stderr, "<- B_BAD_VALUE\n");
89 		return B_BAD_VALUE; // we refuse to crash because you were stupid
90 	}
91 	if (n < 0 || n > fDevices.CountItems() - 1) {
92 		fprintf(stderr, "<- B_BAD_INDEX\n");
93 		return B_BAD_INDEX;
94 	}
95 
96 	MultiAudioDevice *device = (MultiAudioDevice *) fDevices.ItemAt(n);
97 
98 	flavor_info * infos = new flavor_info[1];
99 	MultiAudioNode::GetFlavor(&infos[0], n);
100 	infos[0].name = device->MD.friendly_name;
101 	(*out_info) = infos;
102 	return B_OK;
103 }
104 
105 BMediaNode * MultiAudioAddOn::InstantiateNodeFor(
106 	const flavor_info * info,
107 	BMessage * config,
108 	status_t * out_error)
109 {
110 	CALLED();
111 	if (out_error == 0) {
112 		fprintf(stderr, "<- NULL\n");
113 		return 0; // we refuse to crash because you were stupid
114 	}
115 
116 	MultiAudioDevice *device = (MultiAudioDevice*)fDevices.ItemAt(info->internal_id);
117 	if (device == NULL) {
118 		*out_error = B_ERROR;
119 		return NULL;
120 	}
121 
122 #ifdef MULTI_SAVE
123 	if (fSettings.FindMessage(device->MD.friendly_name, config) == B_OK) {
124 		fSettings.RemoveData(device->MD.friendly_name);
125 	}
126 #endif
127 
128 	MultiAudioNode * node =
129 		new MultiAudioNode(this,
130 			device->MD.friendly_name,
131 			device,
132 			info->internal_id,
133 			config);
134 	if (node == 0) {
135 		*out_error = B_NO_MEMORY;
136 		fprintf(stderr, "<- B_NO_MEMORY\n");
137 	} else {
138 		*out_error = node->InitCheck();
139 	}
140 	return node;
141 }
142 
143 status_t
144 MultiAudioAddOn::GetConfigurationFor(BMediaNode * your_node, BMessage * into_message)
145 {
146 	CALLED();
147 #ifdef MULTI_SAVE
148 	if (into_message == 0) {
149 		into_message = new BMessage();
150 		MultiAudioNode * node = dynamic_cast<MultiAudioNode*>(your_node);
151 		if (node == 0) {
152 			fprintf(stderr, "<- B_BAD_TYPE\n");
153 			return B_BAD_TYPE;
154 		}
155 		if (node->GetConfigurationFor(into_message) == B_OK) {
156 			fSettings.AddMessage(your_node->Name(), into_message);
157 		}
158 		return B_OK;
159 	}
160 #endif
161 	// currently never called by the media kit. Seems it is not implemented.
162 	if (into_message == 0) {
163 		fprintf(stderr, "<- B_BAD_VALUE\n");
164 		return B_BAD_VALUE; // we refuse to crash because you were stupid
165 	}
166 	MultiAudioNode * node = dynamic_cast<MultiAudioNode*>(your_node);
167 	if (node == 0) {
168 		fprintf(stderr, "<- B_BAD_TYPE\n");
169 		return B_BAD_TYPE;
170 	}
171 	return node->GetConfigurationFor(into_message);
172 }
173 
174 
175 bool MultiAudioAddOn::WantsAutoStart()
176 {
177 	CALLED();
178 	return false;
179 }
180 
181 status_t MultiAudioAddOn::AutoStart(
182 	int in_count,
183 	BMediaNode ** out_node,
184 	int32 * out_internal_id,
185 	bool * out_has_more)
186 {
187 	CALLED();
188 	return B_OK;
189 }
190 
191 status_t
192 MultiAudioAddOn::RecursiveScan(char* rootPath, BEntry *rootEntry)
193 {
194 	CALLED();
195 
196 	BDirectory root;
197 	if (rootEntry != NULL)
198 		root.SetTo(rootEntry);
199 	else if (rootPath != NULL) {
200 		root.SetTo(rootPath);
201 	} else {
202 		PRINT(("Error in MultiAudioAddOn::RecursiveScan null params\n"));
203 		return B_ERROR;
204 	}
205 
206 	BEntry entry;
207 
208 	while (root.GetNextEntry(&entry) > B_ERROR) {
209 
210 		if (entry.IsDirectory()) {
211 			RecursiveScan(rootPath, &entry);
212 		} else {
213 			BPath path;
214 			entry.GetPath(&path);
215 			MultiAudioDevice *device = new MultiAudioDevice(path.Path() + strlen(rootPath), path.Path());
216 			if (device) {
217 				if (device->InitCheck() == B_OK)
218 					fDevices.AddItem(device);
219 				else
220 					delete device;
221 			}
222 		}
223 	}
224 
225 	return B_OK;
226 }
227 
228 
229 void
230 MultiAudioAddOn::SaveSettings(void)
231 {
232 	CALLED();
233 	BPath path;
234 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
235 		path.Append(SETTINGS_FILE);
236 		BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
237 		if (file.InitCheck() == B_OK)
238 			fSettings.Flatten(&file);
239 	}
240 }
241 
242 
243 void
244 MultiAudioAddOn::LoadSettings(void)
245 {
246 	CALLED();
247 	fSettings.MakeEmpty();
248 
249 	BPath path;
250 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
251 		path.Append(SETTINGS_FILE);
252 		BFile file(path.Path(), B_READ_ONLY);
253 		if ((file.InitCheck() == B_OK) && (fSettings.Unflatten(&file) == B_OK))
254 		{
255 			PRINT_OBJECT(fSettings);
256 		} else {
257 			PRINT(("Error unflattening settings file %s\n", path.Path()));
258 		}
259 	}
260 }
261