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
26 const char* kSettingsName = "Media/multi_audio_settings";
27
28
29 //! instantiation function
30 extern "C" BMediaAddOn*
make_media_addon(image_id image)31 make_media_addon(image_id image)
32 {
33 CALLED();
34 return new MultiAudioAddOn(image);
35 }
36
37
38 // #pragma mark -
39
40
MultiAudioAddOn(image_id image)41 MultiAudioAddOn::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
~MultiAudioAddOn()55 MultiAudioAddOn::~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
67 status_t
InitCheck(const char ** _failureText)68 MultiAudioAddOn::InitCheck(const char** _failureText)
69 {
70 CALLED();
71 return fInitStatus;
72 }
73
74
75 int32
CountFlavors()76 MultiAudioAddOn::CountFlavors()
77 {
78 CALLED();
79 return fDevices.CountItems();
80 }
81
82
83 status_t
GetFlavorAt(int32 index,const flavor_info ** _info)84 MultiAudioAddOn::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
104 BMediaNode*
InstantiateNodeFor(const flavor_info * info,BMessage * config,status_t * _error)105 MultiAudioAddOn::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
135 status_t
GetConfigurationFor(BMediaNode * _node,BMessage * message)136 MultiAudioAddOn::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
159 bool
WantsAutoStart()160 MultiAudioAddOn::WantsAutoStart()
161 {
162 CALLED();
163 return false;
164 }
165
166
167 status_t
AutoStart(int count,BMediaNode ** _node,int32 * _internalID,bool * _hasMore)168 MultiAudioAddOn::AutoStart(int count, BMediaNode** _node, int32* _internalID,
169 bool* _hasMore)
170 {
171 CALLED();
172 return B_OK;
173 }
174
175
176 status_t
_RecursiveScan(const char * rootPath,BEntry * rootEntry,uint32 depth)177 MultiAudioAddOn::_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
216 void
_SaveSettings()217 MultiAudioAddOn::_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
232 void
_LoadSettings()233 MultiAudioAddOn::_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