xref: /haiku/src/add-ons/media/media-add-ons/esound_sink/ESDSinkAddOn.cpp (revision 922e7ba1f3228e6f28db69b0ded8f86eb32dea17)
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 (n < 0 || n > fDevices.CountItems() - 1) {
117 	if (n < 0 || n > 1) {
118 		fprintf(stderr,"<- B_BAD_INDEX\n");
119 		return B_BAD_INDEX;
120 	}
121 
122 	ESDEndpoint *device = (ESDEndpoint *) fDevices.ItemAt(n);
123 
124 	flavor_info * infos = new flavor_info[1];
125 	ESDSinkNode::GetFlavor(&infos[0], n);
126 //	infos[0].name = device->MD.friendly_name;
127 	infos[0].name = "ESounD Out";
128 	(*out_info) = infos;
129 	return B_OK;
130 }
131 
132 BMediaNode * ESDSinkAddOn::InstantiateNodeFor(
133 				const flavor_info * info,
134 				BMessage * config,
135 				status_t * out_error)
136 {
137 	CALLED();
138 
139 #ifdef MULTI_SAVE
140 	if(fSettings.FindMessage(device->MD.friendly_name, config)==B_OK) {
141 		fSettings.RemoveData(device->MD.friendly_name);
142 	}
143 #endif
144 
145 
146 	ESDSinkNode * node
147 		= new ESDSinkNode(this,
148 						  "ESounD Sink",
149 						  config);
150 	if (node == 0) {
151 		*out_error = B_NO_MEMORY;
152 		fprintf(stderr,"<- B_NO_MEMORY\n");
153 	} else {
154 		*out_error = node->InitCheck();
155 	}
156 	return node;
157 }
158 
159 status_t
160 ESDSinkAddOn::GetConfigurationFor(BMediaNode * your_node, BMessage * into_message)
161 {
162 	CALLED();
163 #ifdef MULTI_SAVE
164 		into_message = new BMessage();
165 		ESDSinkNode * node = dynamic_cast<ESDSinkNode*>(your_node);
166 		if (node == 0) {
167 			fprintf(stderr,"<- B_BAD_TYPE\n");
168 			return B_BAD_TYPE;
169 		}
170 		if(node->GetConfigurationFor(into_message)==B_OK) {
171 			fSettings.AddMessage(your_node->Name(), into_message);
172 		}
173 		return B_OK;
174 #endif
175 	// currently never called by the media kit. Seems it is not implemented.
176 
177 	ESDSinkNode * node = dynamic_cast<ESDSinkNode*>(your_node);
178 	if (node == 0) {
179 		fprintf(stderr,"<- B_BAD_TYPE\n");
180 		return B_BAD_TYPE;
181 	}
182 	return node->GetConfigurationFor(into_message);
183 }
184 
185 #if 0
186 bool ESDSinkAddOn::WantsAutoStart()
187 {
188 	CALLED();
189 	return true;//false;
190 }
191 
192 status_t ESDSinkAddOn::AutoStart(
193 				int in_count,
194 				BMediaNode ** out_node,
195 				int32 * out_internal_id,
196 				bool * out_has_more)
197 {
198 	CALLED();
199 	const flavor_info *fi;
200 	status_t err;
201 
202 	// XXX: LEAK!
203 	PRINT(("AutoStart: in_count=%d\n", in_count));
204 //	if (in_count < 1)
205 //		return EINVAL;
206 	*out_internal_id = 0;
207 	*out_has_more = false;
208 	err = GetFlavorAt(0, (const flavor_info **)&fi);
209 	if (err < 0)
210 		return err;
211 	*out_node = InstantiateNodeFor((const flavor_info *)fi, NULL, &err);
212 	delete fi;
213 	if (err < 0)
214 		return err;
215 	return B_OK+1;
216 }
217 #endif
218 
219 status_t
220 ESDSinkAddOn::SetupDefaultSinks()
221 {
222 	CALLED();
223 #if 0
224 	BDirectory root;
225 	if(rootEntry!=NULL)
226 		root.SetTo(rootEntry);
227 	else if(rootPath!=NULL) {
228 		root.SetTo(rootPath);
229 	} else {
230 		PRINT(("Error in ESDSinkAddOn::RecursiveScan null params\n"));
231 		return B_ERROR;
232 	}
233 
234 	BEntry entry;
235 
236 	while(root.GetNextEntry(&entry) > B_ERROR) {
237 
238 		if(entry.IsDirectory()) {
239 			RecursiveScan(rootPath, &entry);
240 		} else {
241 			BPath path;
242 			entry.GetPath(&path);
243 			ESDEndpoint *device = new ESDEndpoint(path.Path() + strlen(rootPath), path.Path());
244 			if (device) {
245 				if (device->InitCheck() == B_OK)
246 					fDevices.AddItem(device);
247 				else
248 					delete device;
249 			}
250 		}
251 	}
252 
253 #endif
254 	return B_OK;
255 }
256 
257 
258 void
259 ESDSinkAddOn::SaveSettings(void)
260 {
261 	CALLED();
262 	BPath path;
263 	if(find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
264 		path.Append(SETTINGS_FILE);
265 		BFile file(path.Path(),B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE);
266 		if(file.InitCheck()==B_OK)
267 			fSettings.Flatten(&file);
268 	}
269 }
270 
271 
272 void
273 ESDSinkAddOn::LoadSettings(void)
274 {
275 	CALLED();
276 	fSettings.MakeEmpty();
277 
278 	BPath path;
279 	if(find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK) {
280 		path.Append(SETTINGS_FILE);
281 		BFile file(path.Path(),B_READ_ONLY);
282 		if((file.InitCheck()==B_OK)&&(fSettings.Unflatten(&file)==B_OK))
283 		{
284 			//fSettings.PrintToStream();
285 		} else {
286 			PRINT(("Error unflattening settings file %s\n",path.Path()));
287 		}
288 	}
289 }
290