xref: /haiku/src/add-ons/media/media-add-ons/esound_sink/ESDSinkAddOn.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * ESounD media addon for BeOS
3  *
4  * Copyright (c) 2006 François Revol (revol@free.fr)
5  *
6  * Based on Multi Audio addon for Haiku,
7  * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr)
8  *
9  * All rights reserved.
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  *   this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  *   this list of conditions and the following disclaimer in the documentation
17  *   and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 #define _ZETA_TS_FIND_DIR_ 1
32 #include <MediaDefs.h>
33 #include <MediaAddOn.h>
34 #include <Errors.h>
35 #include <Node.h>
36 #include <Mime.h>
37 #include <StorageDefs.h>
38 #include <Path.h>
39 #include <Directory.h>
40 #include <Entry.h>
41 #include <FindDirectory.h>
42 
43 #include "ESDSinkNode.h"
44 #include "ESDSinkAddOn.h"
45 #include "ESDEndpoint.h"
46 
47 #include <limits.h>
48 #include <stdio.h>
49 #include <string.h>
50 //#undef DEBUG
51 //#define DEBUG 4
52 #include "debug.h"
53 #include <Debug.h>
54 
55 //#define MULTI_SAVE
56 
57 // instantiation function
58 extern "C" _EXPORT BMediaAddOn * make_media_addon(image_id image) {
59 	CALLED();
60 	return new ESDSinkAddOn(image);
61 }
62 
63 // -------------------------------------------------------- //
64 // ctor/dtor
65 // -------------------------------------------------------- //
66 
67 ESDSinkAddOn::~ESDSinkAddOn()
68 {
69 	CALLED();
70 
71 	void *device = NULL;
72 	for ( int32 i = 0; (device = fDevices.ItemAt(i)); i++ )
73 		delete (ESDEndpoint *)device;
74 
75 	SaveSettings();
76 }
77 
78 ESDSinkAddOn::ESDSinkAddOn(image_id image) :
79 	BMediaAddOn(image),
80 	fDevices()
81 {
82 	CALLED();
83 	fInitCheckStatus = B_NO_INIT;
84 
85 	LoadSettings();
86 
87 	if(SetupDefaultSinks()!=B_OK)
88 		return;
89 
90 	fInitCheckStatus = B_OK;
91 }
92 
93 // -------------------------------------------------------- //
94 // BMediaAddOn impl
95 // -------------------------------------------------------- //
96 
97 status_t ESDSinkAddOn::InitCheck(
98 	const char ** out_failure_text)
99 {
100 	CALLED();
101 	return B_OK;
102 }
103 
104 int32 ESDSinkAddOn::CountFlavors()
105 {
106 	CALLED();
107 	//return fDevices.CountItems();
108 	return 1;
109 }
110 
111 status_t ESDSinkAddOn::GetFlavorAt(
112 	int32 n,
113 	const flavor_info ** out_info)
114 {
115 	CALLED();
116 	if (out_info == 0) {
117 		fprintf(stderr,"<- B_BAD_VALUE\n");
118 		return B_BAD_VALUE; // we refuse to crash because you were stupid
119 	}
120 	//if (n < 0 || n > fDevices.CountItems() - 1) {
121 	if (n < 0 || n > 1) {
122 		fprintf(stderr,"<- B_BAD_INDEX\n");
123 		return B_BAD_INDEX;
124 	}
125 
126 	ESDEndpoint *device = (ESDEndpoint *) fDevices.ItemAt(n);
127 
128 	flavor_info * infos = new flavor_info[1];
129 	ESDSinkNode::GetFlavor(&infos[0], n);
130 //	infos[0].name = device->MD.friendly_name;
131 	infos[0].name = "ESounD Out";
132 	(*out_info) = infos;
133 	return B_OK;
134 }
135 
136 BMediaNode * ESDSinkAddOn::InstantiateNodeFor(
137 				const flavor_info * info,
138 				BMessage * config,
139 				status_t * out_error)
140 {
141 	CALLED();
142 	if (out_error == 0) {
143 		fprintf(stderr,"<- NULL\n");
144 		return 0; // we refuse to crash because you were stupid
145 	}
146 
147 	BMessage defaults;
148 	if (!config)
149 		config = &defaults;
150 
151 #ifdef MULTI_SAVE
152 	if(fSettings.FindMessage(device->MD.friendly_name, config)==B_OK) {
153 		fSettings.RemoveData(device->MD.friendly_name);
154 	}
155 #endif
156 
157 
158 	ESDSinkNode * node
159 		= new ESDSinkNode(this,
160 						  "ESounD Sink",
161 						  config);
162 	if (node == 0) {
163 		*out_error = B_NO_MEMORY;
164 		fprintf(stderr,"<- B_NO_MEMORY\n");
165 	} else {
166 		*out_error = node->InitCheck();
167 	}
168 	return node;
169 }
170 
171 status_t
172 ESDSinkAddOn::GetConfigurationFor(BMediaNode * your_node, BMessage * into_message)
173 {
174 	CALLED();
175 #ifdef MULTI_SAVE
176 	if (into_message == 0) {
177 		into_message = new BMessage();
178 		ESDSinkNode * node = dynamic_cast<ESDSinkNode*>(your_node);
179 		if (node == 0) {
180 			fprintf(stderr,"<- B_BAD_TYPE\n");
181 			return B_BAD_TYPE;
182 		}
183 		if(node->GetConfigurationFor(into_message)==B_OK) {
184 			fSettings.AddMessage(your_node->Name(), into_message);
185 		}
186 		return B_OK;
187 	}
188 #endif
189 	// currently never called by the media kit. Seems it is not implemented.
190 	if (into_message == 0) {
191 		fprintf(stderr,"<- B_BAD_VALUE\n");
192 		return B_BAD_VALUE; // we refuse to crash because you were stupid
193 	}
194 	ESDSinkNode * node = dynamic_cast<ESDSinkNode*>(your_node);
195 	if (node == 0) {
196 		fprintf(stderr,"<- B_BAD_TYPE\n");
197 		return B_BAD_TYPE;
198 	}
199 	return node->GetConfigurationFor(into_message);
200 }
201 
202 #if 0
203 bool ESDSinkAddOn::WantsAutoStart()
204 {
205 	CALLED();
206 	return true;//false;
207 }
208 
209 status_t ESDSinkAddOn::AutoStart(
210 				int in_count,
211 				BMediaNode ** out_node,
212 				int32 * out_internal_id,
213 				bool * out_has_more)
214 {
215 	CALLED();
216 	const flavor_info *fi;
217 	status_t err;
218 
219 	// XXX: LEAK!
220 	PRINT(("AutoStart: in_count=%d\n", in_count));
221 //	if (in_count < 1)
222 //		return EINVAL;
223 	*out_internal_id = 0;
224 	*out_has_more = false;
225 	err = GetFlavorAt(0, (const flavor_info **)&fi);
226 	if (err < 0)
227 		return err;
228 	*out_node = InstantiateNodeFor((const flavor_info *)fi, NULL, &err);
229 	delete fi;
230 	if (err < 0)
231 		return err;
232 	return B_OK+1;
233 }
234 #endif
235 
236 status_t
237 ESDSinkAddOn::SetupDefaultSinks()
238 {
239 	CALLED();
240 #if 0
241 	BDirectory root;
242 	if(rootEntry!=NULL)
243 		root.SetTo(rootEntry);
244 	else if(rootPath!=NULL) {
245 		root.SetTo(rootPath);
246 	} else {
247 		PRINT(("Error in ESDSinkAddOn::RecursiveScan null params\n"));
248 		return B_ERROR;
249 	}
250 
251 	BEntry entry;
252 
253 	while(root.GetNextEntry(&entry) > B_ERROR) {
254 
255 		if(entry.IsDirectory()) {
256 			RecursiveScan(rootPath, &entry);
257 		} else {
258 			BPath path;
259 			entry.GetPath(&path);
260 			ESDEndpoint *device = new ESDEndpoint(path.Path() + strlen(rootPath), path.Path());
261 			if (device) {
262 				if (device->InitCheck() == B_OK)
263 					fDevices.AddItem(device);
264 				else
265 					delete device;
266 			}
267 		}
268 	}
269 
270 #endif
271 	return B_OK;
272 }
273 
274 
275 void
276 ESDSinkAddOn::SaveSettings(void)
277 {
278 	CALLED();
279 	BPath path;
280 	if(find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
281 		path.Append(SETTINGS_FILE);
282 		BFile file(path.Path(),B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
283 		if(file.InitCheck()==B_OK)
284 			fSettings.Flatten(&file);
285 	}
286 }
287 
288 
289 void
290 ESDSinkAddOn::LoadSettings(void)
291 {
292 	CALLED();
293 	fSettings.MakeEmpty();
294 
295 	BPath path;
296 	if(find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
297 		path.Append(SETTINGS_FILE);
298 		BFile file(path.Path(),B_READ_ONLY);
299 		if((file.InitCheck()==B_OK)&&(fSettings.Unflatten(&file)==B_OK))
300 		{
301 			//fSettings.PrintToStream();
302 		} else {
303 			PRINT(("Error unflattening settings file %s\n",path.Path()));
304 		}
305 	}
306 }
307