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