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