1242094dbSshatty// AbstractFileInterfaceNode.cpp
2242094dbSshatty//
3242094dbSshatty// Andrew Bachmann, 2002
4242094dbSshatty//
5242094dbSshatty// The AbstractFileInterfaceNode class implements
6242094dbSshatty// the common functionality between MediaReader
7242094dbSshatty// and MediaWriter.
8fb16552fSMaurice Kalinowski#include "AbstractFileInterfaceNode.h"
9fb16552fSMaurice Kalinowski#include "debug.h"
10242094dbSshatty
11fb16552fSMaurice Kalinowski#include <Buffer.h>
12242094dbSshatty#include <Controllable.h>
13242094dbSshatty#include <Entry.h>
14fb16552fSMaurice Kalinowski#include <Errors.h>
15fb16552fSMaurice Kalinowski#include <File.h>
16fb16552fSMaurice Kalinowski#include <FileInterface.h>
17fb16552fSMaurice Kalinowski#include <MediaDefs.h>
18fb16552fSMaurice Kalinowski#include <MediaEventLooper.h>
19fb16552fSMaurice Kalinowski#include <MediaNode.h>
20242094dbSshatty#include <TimeSource.h>
21242094dbSshatty#include <ParameterWeb.h>
22242094dbSshatty#include <limits.h>
23242094dbSshatty#include <stdio.h>
24242094dbSshatty#include <string.h>
25242094dbSshatty
26242094dbSshatty
27242094dbSshattyAbstractFileInterfaceNode::~AbstractFileInterfaceNode(void)
28242094dbSshatty{
29fb16552fSMaurice Kalinowski	CALLED();
30fb16552fSMaurice Kalinowski
31242094dbSshatty	// Stop the BMediaEventLooper thread
32242094dbSshatty	Quit();
33fb16552fSMaurice Kalinowski	if (fCurrentFile != 0)
34242094dbSshatty		delete fCurrentFile;
35242094dbSshatty}
36242094dbSshatty
37fb16552fSMaurice Kalinowski
38242094dbSshattyAbstractFileInterfaceNode::AbstractFileInterfaceNode(
39fb16552fSMaurice Kalinowski				size_t defaultChunkSize,
40fb16552fSMaurice Kalinowski				float defaultBitRate,
41fb16552fSMaurice Kalinowski				const flavor_info * info,
42fb16552fSMaurice Kalinowski				BMessage * config,
43fb16552fSMaurice Kalinowski				BMediaAddOn * addOn)
44242094dbSshatty	: BMediaNode("AbstractFileInterfaceNode"),
45242094dbSshatty	  BFileInterface(),
46242094dbSshatty	  BControllable(),
47242094dbSshatty	  BMediaEventLooper()
48242094dbSshatty{
49fb16552fSMaurice Kalinowski	CALLED();
50fb16552fSMaurice Kalinowski
51242094dbSshatty	// keep our creator around for AddOn calls later
52242094dbSshatty	fAddOn = addOn;
53242094dbSshatty	// null some fields
54242094dbSshatty	fCurrentFile = 0;
55242094dbSshatty	f_current_mime_type[0] = '\0';
56fb16552fSMaurice Kalinowski
57242094dbSshatty	// initialize the parameters
58242094dbSshatty	if (defaultChunkSize <= 0) {
59242094dbSshatty		fInitCheckStatus = B_BAD_VALUE;
60242094dbSshatty		return;
61242094dbSshatty	}
62fb16552fSMaurice Kalinowski
63242094dbSshatty	fDefaultChunkSizeParam = defaultChunkSize;
64242094dbSshatty	fDefaultChunkSizeParamChangeTime = 0;
65242094dbSshatty	if (defaultBitRate <= 0) {
66242094dbSshatty		fInitCheckStatus = B_BAD_VALUE;
67242094dbSshatty		return;
68242094dbSshatty	}
69fb16552fSMaurice Kalinowski
70242094dbSshatty	fDefaultBitRateParam = defaultBitRate;
71242094dbSshatty	fDefaultBitRateParamChangeTime = 0;
72242094dbSshatty	// initialize parameter compute fields
73242094dbSshatty	fLeastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM;
74242094dbSshatty	fLastUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM;
75242094dbSshatty	// From the chunk size and bit rate we compute the buffer period.
76242094dbSshatty	int64 value = int64(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam);
77242094dbSshatty	if ((value <= 0) || (value > INT_MAX)) {
78242094dbSshatty		fInitCheckStatus = B_BAD_VALUE;
79242094dbSshatty		return;
80242094dbSshatty	}
81242094dbSshatty	fDefaultBufferPeriodParam = int32(value);
82242094dbSshatty	fDefaultBufferPeriodParamChangeTime = 0;
83242094dbSshatty
84242094dbSshatty	fInitCheckStatus = B_OK;
85242094dbSshatty}
86242094dbSshatty
87fb16552fSMaurice Kalinowski
88242094dbSshattystatus_t AbstractFileInterfaceNode::InitCheck(void) const
89242094dbSshatty{
90fb16552fSMaurice Kalinowski	CALLED();
91242094dbSshatty	return fInitCheckStatus;
92242094dbSshatty}
93242094dbSshatty
94fb16552fSMaurice Kalinowski
95242094dbSshattystatus_t AbstractFileInterfaceNode::GetConfigurationFor(
96242094dbSshatty				BMessage * into_message)
97242094dbSshatty{
98fb16552fSMaurice Kalinowski	CALLED();
99242094dbSshatty	return B_OK;
100242094dbSshatty}
101242094dbSshatty
102fb16552fSMaurice Kalinowski
103242094dbSshatty// -------------------------------------------------------- //
104242094dbSshatty// implementation of BMediaNode
105242094dbSshatty// -------------------------------------------------------- //
106242094dbSshattyBMediaAddOn * AbstractFileInterfaceNode::AddOn(
107242094dbSshatty				int32 * internal_id) const
108242094dbSshatty{
109fb16552fSMaurice Kalinowski	CALLED();
110242094dbSshatty	// BeBook says this only gets called if we were in an add-on.
111242094dbSshatty	if (fAddOn != 0) {
112242094dbSshatty		// If we get a null pointer then we just won't write.
113fb16552fSMaurice Kalinowski		if (internal_id != 0)
114242094dbSshatty			internal_id = 0;
115242094dbSshatty	}
116242094dbSshatty	return fAddOn;
117242094dbSshatty}
118242094dbSshatty
119fb16552fSMaurice Kalinowski
120242094dbSshattyvoid AbstractFileInterfaceNode::Start(
121242094dbSshatty				bigtime_t performance_time)
122242094dbSshatty{
123fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::Start(pt=%lld)\n",performance_time);
124242094dbSshatty	BMediaEventLooper::Start(performance_time);
125242094dbSshatty}
126242094dbSshatty
127fb16552fSMaurice Kalinowski
128242094dbSshattyvoid AbstractFileInterfaceNode::Stop(
129242094dbSshatty				bigtime_t performance_time,
130242094dbSshatty				bool immediate)
131242094dbSshatty{
132fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::Stop(pt=%lld, im=%d)\n",
133fb16552fSMaurice Kalinowski		  performance_time, immediate);
134242094dbSshatty	BMediaEventLooper::Stop(performance_time,immediate);
135242094dbSshatty}
136242094dbSshatty
137fb16552fSMaurice Kalinowski
138242094dbSshattyvoid AbstractFileInterfaceNode::Seek(
139242094dbSshatty				bigtime_t media_time,
140242094dbSshatty				bigtime_t performance_time)
141242094dbSshatty{
142fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::Seek(mt=%lld,pt=%lld)\n",
143fb16552fSMaurice Kalinowski		  media_time,performance_time);
144242094dbSshatty	BMediaEventLooper::Seek(media_time,performance_time);
145242094dbSshatty}
146242094dbSshatty
147fb16552fSMaurice Kalinowski
148242094dbSshattyvoid AbstractFileInterfaceNode::SetRunMode(
149242094dbSshatty				run_mode mode)
150242094dbSshatty{
151fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::SetRunMode(%i)\n",mode);
152242094dbSshatty	BMediaEventLooper::SetRunMode(mode);
153242094dbSshatty}
154242094dbSshatty
155fb16552fSMaurice Kalinowski
156242094dbSshattyvoid AbstractFileInterfaceNode::TimeWarp(
157242094dbSshatty				bigtime_t at_real_time,
158242094dbSshatty				bigtime_t to_performance_time)
159242094dbSshatty{
160fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::TimeWarp(rt=%lld,pt=%lld)\n",
161fb16552fSMaurice Kalinowski		  at_real_time,to_performance_time);
162242094dbSshatty	BMediaEventLooper::TimeWarp(at_real_time,to_performance_time);
163242094dbSshatty}
164242094dbSshatty
165fb16552fSMaurice Kalinowski
166242094dbSshattyvoid AbstractFileInterfaceNode::Preroll(void)
167242094dbSshatty{
168fb16552fSMaurice Kalinowski	CALLED();
169242094dbSshatty	// XXX:Performance opportunity
170242094dbSshatty	BMediaNode::Preroll();
171242094dbSshatty}
172242094dbSshatty
173fb16552fSMaurice Kalinowski
174242094dbSshattyvoid AbstractFileInterfaceNode::SetTimeSource(
175242094dbSshatty				BTimeSource * time_source)
176242094dbSshatty{
177fb16552fSMaurice Kalinowski	CALLED();
178242094dbSshatty	BMediaNode::SetTimeSource(time_source);
179242094dbSshatty}
180242094dbSshatty
181fb16552fSMaurice Kalinowski
182242094dbSshattystatus_t AbstractFileInterfaceNode::HandleMessage(
183242094dbSshatty				int32 message,
184242094dbSshatty				const void * data,
185242094dbSshatty				size_t size)
186242094dbSshatty{
187fb16552fSMaurice Kalinowski	CALLED();
188fb16552fSMaurice Kalinowski
189242094dbSshatty	status_t status = B_OK;
190242094dbSshatty	switch (message) {
191242094dbSshatty		// no special messages for now
192242094dbSshatty		default:
193242094dbSshatty			status = BFileInterface::HandleMessage(message,data,size);
194242094dbSshatty			if (status == B_OK) {
195242094dbSshatty				break;
196242094dbSshatty			}
197fb16552fSMaurice Kalinowski			status = BControllable::HandleMessage(message, data, size);
198fb16552fSMaurice Kalinowski			if (status == B_OK)
199fb16552fSMaurice Kalinowski				break;
200242094dbSshatty			status = BMediaNode::HandleMessage(message,data,size);
201242094dbSshatty			if (status == B_OK) {
202242094dbSshatty				break;
203242094dbSshatty			}
204242094dbSshatty			BMediaNode::HandleBadMessage(message,data,size);
205242094dbSshatty			status = B_ERROR;
206242094dbSshatty			break;
207242094dbSshatty	}
208242094dbSshatty	return status;
209242094dbSshatty}
210242094dbSshatty
211fb16552fSMaurice Kalinowski
212242094dbSshattystatus_t AbstractFileInterfaceNode::RequestCompleted(
213242094dbSshatty				const media_request_info & info)
214242094dbSshatty{
215fb16552fSMaurice Kalinowski	CALLED();
216242094dbSshatty	return BMediaNode::RequestCompleted(info);
217242094dbSshatty}
218242094dbSshatty
219fb16552fSMaurice Kalinowski
220242094dbSshattystatus_t AbstractFileInterfaceNode::DeleteHook(
221242094dbSshatty				BMediaNode * node)
222242094dbSshatty{
223fb16552fSMaurice Kalinowski	CALLED();
224242094dbSshatty	return BMediaEventLooper::DeleteHook(node);
225242094dbSshatty}
226242094dbSshatty
227fb16552fSMaurice Kalinowski
228242094dbSshattyvoid AbstractFileInterfaceNode::NodeRegistered(void)
229242094dbSshatty{
230fb16552fSMaurice Kalinowski	CALLED();
231242094dbSshatty
232242094dbSshatty	// set up our parameter web
233242094dbSshatty	SetParameterWeb(MakeParameterWeb());
234242094dbSshatty
235242094dbSshatty	// start the BMediaEventLooper thread
236242094dbSshatty	SetPriority(B_REAL_TIME_PRIORITY);
237242094dbSshatty	Run();
238242094dbSshatty}
239242094dbSshatty
240fb16552fSMaurice Kalinowski
241242094dbSshattystatus_t AbstractFileInterfaceNode::GetNodeAttributes(
242242094dbSshatty				media_node_attribute * outAttributes,
243242094dbSshatty				size_t inMaxCount)
244242094dbSshatty{
245fb16552fSMaurice Kalinowski	CALLED();
246242094dbSshatty	return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount);
247242094dbSshatty}
248242094dbSshatty
249fb16552fSMaurice Kalinowski
250242094dbSshattystatus_t AbstractFileInterfaceNode::AddTimer(
251242094dbSshatty					bigtime_t at_performance_time,
252242094dbSshatty					int32 cookie)
253242094dbSshatty{
254fb16552fSMaurice Kalinowski	CALLED();
255242094dbSshatty	return BMediaEventLooper::AddTimer(at_performance_time,cookie);
256242094dbSshatty}
257242094dbSshatty
258242094dbSshatty
259fb16552fSMaurice Kalinowski// protected:
260242094dbSshattyBParameterWeb * AbstractFileInterfaceNode::MakeParameterWeb(void)
261242094dbSshatty{
262fb16552fSMaurice Kalinowski	CALLED();
263242094dbSshatty
264242094dbSshatty	BParameterWeb * web = new BParameterWeb();
265242094dbSshatty	BParameterGroup * mainGroup = web->MakeGroup("AbstractFileInterfaceNode Parameters");
266242094dbSshatty
267242094dbSshatty	// these three are related:
268fb16552fSMaurice Kalinowski	// DEFAULT_CHUNK_SIZE_PARAM =
269fb16552fSMaurice Kalinowski	// DEFAULT_BIT_RATE_PARAM / 1024 * DEFAULT_BUFFER_PERIOD_PARAM * 1000
270242094dbSshatty	BParameterGroup * chunkSizeGroup = mainGroup->MakeGroup("Chunk Size Group");
271242094dbSshatty	BContinuousParameter * chunkSizeParameter
272242094dbSshatty	   = chunkSizeGroup->MakeContinuousParameter(
273242094dbSshatty	     DEFAULT_CHUNK_SIZE_PARAM, B_MEDIA_MULTISTREAM,
274242094dbSshatty		 "Chunk Size", B_GAIN, "bytes", 1024, 32*1024, 512);
275242094dbSshatty	chunkSizeParameter->SetResponse(BContinuousParameter::B_LINEAR,1,0);
276242094dbSshatty	chunkSizeParameter->SetValue(&fDefaultChunkSizeParam,sizeof(fDefaultChunkSizeParam),0);
277242094dbSshatty
278242094dbSshatty	BParameterGroup * bitRateGroup = mainGroup->MakeGroup("Bit Rate Group");
279242094dbSshatty	BContinuousParameter * bitRateParameter
280242094dbSshatty	   = bitRateGroup->MakeContinuousParameter(
281242094dbSshatty	     DEFAULT_BIT_RATE_PARAM, B_MEDIA_MULTISTREAM,
282242094dbSshatty	     "Bit Rate", B_GAIN, "kbits/sec", 1, 320000, 1);
283242094dbSshatty	bitRateParameter->SetResponse(BContinuousParameter::B_LINEAR,.001,0);
284242094dbSshatty	bitRateParameter->SetValue(&fDefaultBitRateParam,sizeof(fDefaultBitRateParam),0);
285242094dbSshatty
286242094dbSshatty	BParameterGroup * bufferPeriodGroup = mainGroup->MakeGroup("Buffer Period Group");
287242094dbSshatty	BContinuousParameter * bufferPeriodParameter
288242094dbSshatty	   = bufferPeriodGroup->MakeContinuousParameter(
289242094dbSshatty	     DEFAULT_BUFFER_PERIOD_PARAM, B_MEDIA_MULTISTREAM,
290242094dbSshatty	     "Buffer Period", B_GAIN, "ms", 1, 10000, 1);
291242094dbSshatty	bufferPeriodParameter->SetResponse(BContinuousParameter::B_LINEAR,1,0);
292242094dbSshatty	bufferPeriodParameter->SetValue(&fDefaultBufferPeriodParam,sizeof(fDefaultBufferPeriodParam),0);
293242094dbSshatty
294242094dbSshatty	return web;
295242094dbSshatty}
296242094dbSshatty
297fb16552fSMaurice Kalinowski
298242094dbSshatty// -------------------------------------------------------- //
299242094dbSshatty// implementation of BFileInterface
300242094dbSshatty// -------------------------------------------------------- //
301242094dbSshattystatus_t AbstractFileInterfaceNode::GetNextFileFormat(
302242094dbSshatty				int32 * cookie,
303242094dbSshatty				media_file_format * out_format)
304242094dbSshatty{
305fb16552fSMaurice Kalinowski	CALLED();
306fb16552fSMaurice Kalinowski
307bcf291edSMarcus Overhagen	// it's valid but they already got our 1 file format
308bcf291edSMarcus Overhagen	if (*cookie != 0) {
309bcf291edSMarcus Overhagen		PRINT("\t<- B_ERROR\n");
310bcf291edSMarcus Overhagen		return B_ERROR;
311242094dbSshatty	}
312fb16552fSMaurice Kalinowski
313bcf291edSMarcus Overhagen	// so next time they won't get the same format again
314bcf291edSMarcus Overhagen	*cookie = 1;
31545ed7b19Sshatty	GetFileFormat(out_format);
316242094dbSshatty	return B_OK;
317242094dbSshatty}
318242094dbSshatty
319fb16552fSMaurice Kalinowski
320242094dbSshattyvoid AbstractFileInterfaceNode::DisposeFileFormatCookie(
321242094dbSshatty				int32 cookie)
322242094dbSshatty{
323fb16552fSMaurice Kalinowski	CALLED();
324242094dbSshatty	// nothing to do since our cookies are just integers
325242094dbSshatty}
326242094dbSshatty
327fb16552fSMaurice Kalinowski
328242094dbSshattystatus_t AbstractFileInterfaceNode::GetDuration(
329242094dbSshatty				bigtime_t * out_time)
330242094dbSshatty{
331fb16552fSMaurice Kalinowski	CALLED();
332242094dbSshatty	if (out_time == 0) {
333fb16552fSMaurice Kalinowski		PRINT("\t<- B_BAD_VALUE\n");
334242094dbSshatty		return B_BAD_VALUE;
335242094dbSshatty	}
336fb16552fSMaurice Kalinowski
337242094dbSshatty	if (fCurrentFile == 0) {
338fb16552fSMaurice Kalinowski		PRINT("\t<- B_NO_INIT\n");
339242094dbSshatty		return B_NO_INIT;
340242094dbSshatty	}
341fb16552fSMaurice Kalinowski
342242094dbSshatty	return fCurrentFile->GetSize(out_time);
343242094dbSshatty}
344242094dbSshatty
345fb16552fSMaurice Kalinowski
346242094dbSshattystatus_t AbstractFileInterfaceNode::SniffRef(
347242094dbSshatty				const entry_ref & file,
348242094dbSshatty				char * out_mime_type,	/* 256 bytes */
349242094dbSshatty				float * out_quality)
350242094dbSshatty{
351fb16552fSMaurice Kalinowski	CALLED();
352242094dbSshatty	return StaticSniffRef(file,out_mime_type,out_quality);
353242094dbSshatty}
354242094dbSshatty
355fb16552fSMaurice Kalinowski
356242094dbSshattystatus_t AbstractFileInterfaceNode::SetRef(
357242094dbSshatty				const entry_ref & file,
358242094dbSshatty				uint32 openMode,
359242094dbSshatty				bool create,
360242094dbSshatty				bigtime_t * out_time)
361242094dbSshatty{
362fb16552fSMaurice Kalinowski	CALLED();
363fb16552fSMaurice Kalinowski
364242094dbSshatty	status_t status;
365242094dbSshatty	f_current_ref = file;
366242094dbSshatty	if (fCurrentFile == 0) {
367242094dbSshatty		fCurrentFile = new BFile(&f_current_ref,(openMode|(create?B_CREATE_FILE:0)));
368242094dbSshatty		status = fCurrentFile->InitCheck();
369242094dbSshatty	} else {
370242094dbSshatty		status = fCurrentFile->SetTo(&f_current_ref,(openMode|(create?B_CREATE_FILE:0)));
371242094dbSshatty	}
372fb16552fSMaurice Kalinowski
373242094dbSshatty	if (status != B_OK) {
374fb16552fSMaurice Kalinowski		PRINT("\t<- failed BFile initialization\n");
375242094dbSshatty		return status;
376242094dbSshatty	}
377fb16552fSMaurice Kalinowski
378242094dbSshatty	// cache the mime type for later
379242094dbSshatty	fCurrentFile->ReadAttr("BEOS:TYPE",0,0,f_current_mime_type,B_MIME_TYPE_LENGTH);
380242094dbSshatty	// compute the duration and return any error
381242094dbSshatty	return GetDuration(out_time);
382242094dbSshatty}
383242094dbSshatty
384fb16552fSMaurice Kalinowski
385242094dbSshattystatus_t AbstractFileInterfaceNode::GetRef(
386242094dbSshatty				entry_ref * out_ref,
387242094dbSshatty				char * out_mime_type)
388242094dbSshatty{
389fb16552fSMaurice Kalinowski	CALLED();
390fb16552fSMaurice Kalinowski
391242094dbSshatty	if (fCurrentFile == 0) {
392fb16552fSMaurice Kalinowski		PRINT("\t<- B_NO_INIT\n");
393242094dbSshatty		return B_NO_INIT; // the input_ref isn't valid yet either
394242094dbSshatty	}
395fb16552fSMaurice Kalinowski
396242094dbSshatty	*out_ref = f_current_ref;
397242094dbSshatty	// they hopefully allocated enough space (no way to check :-/ )
398242094dbSshatty	strcpy(out_mime_type,f_current_mime_type);
399242094dbSshatty	return B_OK;
400242094dbSshatty}
401242094dbSshatty
402242094dbSshatty
403fb16552fSMaurice Kalinowski// provided for BAbstractFileInterfaceNodeAddOn
404242094dbSshattystatus_t AbstractFileInterfaceNode::StaticSniffRef(
405242094dbSshatty				const entry_ref & file,
406242094dbSshatty				char * out_mime_type,	/* 256 bytes */
407242094dbSshatty				float * out_quality)
408242094dbSshatty{
409fb16552fSMaurice Kalinowski	CALLED();
410fb16552fSMaurice Kalinowski
411242094dbSshatty	BNode node(&file);
412242094dbSshatty	status_t initCheck = node.InitCheck();
413242094dbSshatty	if (initCheck != B_OK) {
414fb16552fSMaurice Kalinowski		PRINT("\t<- failed BNode::InitCheck()\n");
415242094dbSshatty		return initCheck;
416242094dbSshatty	}
417fb16552fSMaurice Kalinowski
418242094dbSshatty	// they hopefully allocated enough room
419242094dbSshatty	node.ReadAttr("BEOS:TYPE",0,0,out_mime_type,B_MIME_TYPE_LENGTH);
420242094dbSshatty	*out_quality = 1.0; // we handle all files perfectly!  we are so amazing!
421242094dbSshatty	return B_OK;
422242094dbSshatty}
423242094dbSshatty
424fb16552fSMaurice Kalinowski
425242094dbSshatty// -------------------------------------------------------- //
426242094dbSshatty// implementation for BControllable
427242094dbSshatty// -------------------------------------------------------- //
428242094dbSshattyconst int32 AbstractFileInterfaceNode::DEFAULT_CHUNK_SIZE_PARAM = 1;
429242094dbSshattyconst int32 AbstractFileInterfaceNode::DEFAULT_BIT_RATE_PARAM = 2;
430242094dbSshattyconst int32 AbstractFileInterfaceNode::DEFAULT_BUFFER_PERIOD_PARAM = 3;
431242094dbSshatty
432fb16552fSMaurice Kalinowski
433242094dbSshattystatus_t AbstractFileInterfaceNode::GetParameterValue(
434242094dbSshatty				int32 id,
435242094dbSshatty				bigtime_t * last_change,
436242094dbSshatty				void * value,
437242094dbSshatty				size_t * ioSize)
438242094dbSshatty{
439fb16552fSMaurice Kalinowski	CALLED();
440fb16552fSMaurice Kalinowski
441242094dbSshatty	switch (id) {
442242094dbSshatty		case DEFAULT_CHUNK_SIZE_PARAM:
443242094dbSshatty			if (*ioSize < sizeof(size_t)) {
444242094dbSshatty				return B_ERROR; // not enough room
445242094dbSshatty			}
446242094dbSshatty			*last_change = fDefaultChunkSizeParamChangeTime;
447242094dbSshatty			*((size_t*)value) = fDefaultChunkSizeParam;
448242094dbSshatty			*ioSize = sizeof(size_t);
449242094dbSshatty			break;
450242094dbSshatty
451242094dbSshatty		case DEFAULT_BIT_RATE_PARAM:
452242094dbSshatty			if (*ioSize < sizeof(float)) {
453242094dbSshatty				return B_ERROR; // not enough room
454242094dbSshatty			}
455242094dbSshatty			*last_change = fDefaultBitRateParamChangeTime;
456242094dbSshatty			*((float*)value) = fDefaultBitRateParam;
457242094dbSshatty			*ioSize = sizeof(float);
458242094dbSshatty			break;
459242094dbSshatty
460242094dbSshatty		case DEFAULT_BUFFER_PERIOD_PARAM:
461242094dbSshatty			if (*ioSize < sizeof(int32)) {
462242094dbSshatty				return B_ERROR; // not enough room
463242094dbSshatty			}
464242094dbSshatty			*last_change = fDefaultBufferPeriodParamChangeTime;
465242094dbSshatty			*((int32*)value) = fDefaultBufferPeriodParam;
466242094dbSshatty			*ioSize = sizeof(int32);
467242094dbSshatty			break;
468242094dbSshatty
469242094dbSshatty		default:
470fb16552fSMaurice Kalinowski			PRINT("AbstractFileInterfaceNode::GetParameterValue unknown id (%ld)\n",id);
471242094dbSshatty			return B_ERROR;
472242094dbSshatty	}
473fb16552fSMaurice Kalinowski
474fb16552fSMaurice Kalinowski	return B_OK;
475242094dbSshatty}
476fb16552fSMaurice Kalinowski
477fb16552fSMaurice Kalinowski
478242094dbSshattyvoid AbstractFileInterfaceNode::SetParameterValue(
479242094dbSshatty				int32 id,
480242094dbSshatty				bigtime_t when,
481242094dbSshatty				const void * value,
482242094dbSshatty				size_t size)
483242094dbSshatty{
484fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::SetParameterValue(id=%ld,when=%lld,size=%ld)\n",id,when,int32(size));
485fb16552fSMaurice Kalinowski
486242094dbSshatty	switch (id) {
487242094dbSshatty		case DEFAULT_CHUNK_SIZE_PARAM:
488242094dbSshatty		case DEFAULT_BIT_RATE_PARAM:
489242094dbSshatty		case DEFAULT_BUFFER_PERIOD_PARAM:
490242094dbSshatty			{
491242094dbSshatty				media_timed_event event(when, BTimedEventQueue::B_PARAMETER,
492242094dbSshatty										NULL, BTimedEventQueue::B_NO_CLEANUP,
493242094dbSshatty										size, id, (char*) value, size);
494242094dbSshatty				EventQueue()->AddEvent(event);
495242094dbSshatty			}
496242094dbSshatty			break;
497242094dbSshatty
498242094dbSshatty		default:
499fb16552fSMaurice Kalinowski			PRINT("AbstractFileInterfaceNode::SetParameterValue unknown id (%ld)\n",id);
500242094dbSshatty			break;
501242094dbSshatty	}
502242094dbSshatty}
503242094dbSshatty
504fb16552fSMaurice Kalinowski
505242094dbSshatty// the default implementation should call the add-on main()
506242094dbSshattystatus_t AbstractFileInterfaceNode::StartControlPanel(
507242094dbSshatty				BMessenger * out_messenger)
508242094dbSshatty{
509fb16552fSMaurice Kalinowski	CALLED();
510fb16552fSMaurice Kalinowski	return BControllable::StartControlPanel(out_messenger);
511242094dbSshatty}
512242094dbSshatty
513fb16552fSMaurice Kalinowski
514242094dbSshatty// -------------------------------------------------------- //
515242094dbSshatty// implementation for BMediaEventLooper
516242094dbSshatty// -------------------------------------------------------- //
517242094dbSshattyvoid AbstractFileInterfaceNode::HandleEvent(
518242094dbSshatty				const media_timed_event *event,
519242094dbSshatty				bigtime_t lateness,
520fb16552fSMaurice Kalinowski				bool realTimeEvent)
521242094dbSshatty{
522fb16552fSMaurice Kalinowski	CALLED();
523242094dbSshatty	switch (event->type) {
524242094dbSshatty		case BTimedEventQueue::B_START:
525242094dbSshatty			HandleStart(event,lateness,realTimeEvent);
526242094dbSshatty			break;
527242094dbSshatty		case BTimedEventQueue::B_SEEK:
528242094dbSshatty			HandleSeek(event,lateness,realTimeEvent);
529242094dbSshatty			break;
530242094dbSshatty		case BTimedEventQueue::B_WARP:
531242094dbSshatty			HandleWarp(event,lateness,realTimeEvent);
532242094dbSshatty			break;
533242094dbSshatty		case BTimedEventQueue::B_STOP:
534242094dbSshatty			HandleStop(event,lateness,realTimeEvent);
535242094dbSshatty			break;
536242094dbSshatty		case BTimedEventQueue::B_HANDLE_BUFFER:
537242094dbSshatty			if (RunState() == BMediaEventLooper::B_STARTED) {
538242094dbSshatty				HandleBuffer(event,lateness,realTimeEvent);
539242094dbSshatty			}
540242094dbSshatty			break;
541242094dbSshatty		case BTimedEventQueue::B_DATA_STATUS:
542242094dbSshatty			HandleDataStatus(event,lateness,realTimeEvent);
543242094dbSshatty			break;
544242094dbSshatty		case BTimedEventQueue::B_PARAMETER:
545242094dbSshatty			HandleParameter(event,lateness,realTimeEvent);
546242094dbSshatty			break;
547242094dbSshatty		default:
548fb16552fSMaurice Kalinowski			PRINT("  unknown event type: %ld\n",event->type);
549242094dbSshatty			break;
550242094dbSshatty	}
551242094dbSshatty}
552242094dbSshatty
553fb16552fSMaurice Kalinowski
554242094dbSshatty/* override to clean up custom events you have added to your queue */
555242094dbSshattyvoid AbstractFileInterfaceNode::CleanUpEvent(
556242094dbSshatty				const media_timed_event *event)
557242094dbSshatty{
558242094dbSshatty	BMediaEventLooper::CleanUpEvent(event);
559242094dbSshatty}
560fb16552fSMaurice Kalinowski
561fb16552fSMaurice Kalinowski
562242094dbSshatty/* called from Offline mode to determine the current time of the node */
563242094dbSshatty/* update your internal information whenever it changes */
564242094dbSshattybigtime_t AbstractFileInterfaceNode::OfflineTime()
565242094dbSshatty{
566fb16552fSMaurice Kalinowski	CALLED();
567242094dbSshatty	return BMediaEventLooper::OfflineTime();
568fb16552fSMaurice Kalinowski	// XXX: do something else?
569fb16552fSMaurice Kalinowski	//	if (inputFile == 0) {
570fb16552fSMaurice Kalinowski	//		return 0;
571fb16552fSMaurice Kalinowski	//	} else {
572fb16552fSMaurice Kalinowski	//		return inputFile->Position();
573fb16552fSMaurice Kalinowski	//	}
574242094dbSshatty}
575242094dbSshatty
576fb16552fSMaurice Kalinowski
577242094dbSshatty/* override only if you know what you are doing! */
578242094dbSshatty/* otherwise much badness could occur */
579242094dbSshatty/* the actual control loop function: */
580242094dbSshatty/* 	waits for messages, Pops events off the queue and calls DispatchEvent */
581242094dbSshattyvoid AbstractFileInterfaceNode::ControlLoop() {
582242094dbSshatty	BMediaEventLooper::ControlLoop();
583242094dbSshatty}
584242094dbSshatty
585242094dbSshatty
586fb16552fSMaurice Kalinowski// protected:
587242094dbSshattystatus_t AbstractFileInterfaceNode::HandleStart(
588242094dbSshatty						const media_timed_event *event,
589242094dbSshatty						bigtime_t lateness,
590fb16552fSMaurice Kalinowski						bool realTimeEvent)
591242094dbSshatty{
592fb16552fSMaurice Kalinowski	CALLED();
593fb16552fSMaurice Kalinowski
594242094dbSshatty	if (RunState() != B_STARTED) {
595fb16552fSMaurice Kalinowski		// XXX: Either use the following line or the lines that are not commented.
596fb16552fSMaurice Kalinowski		// There doesn't seem to be a practical difference that i can tell.
597fb16552fSMaurice Kalinowski		//		HandleBuffer(event,lateness,realTimeEvent);
598981e4127Sshatty		media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER);
599981e4127Sshatty		HandleEvent(&firstBufferEvent, 0, false);
600981e4127Sshatty		EventQueue()->AddEvent(firstBufferEvent);
601242094dbSshatty	}
602fb16552fSMaurice Kalinowski	return B_OK;
603242094dbSshatty}
604242094dbSshatty
605fb16552fSMaurice Kalinowski
606242094dbSshattystatus_t AbstractFileInterfaceNode::HandleSeek(
607242094dbSshatty						const media_timed_event *event,
608242094dbSshatty						bigtime_t lateness,
609fb16552fSMaurice Kalinowski						bool realTimeEvent)
610242094dbSshatty{
611fb16552fSMaurice Kalinowski	PRINT("AbstractFileInterfaceNode::HandleSeek(t=%lld,d=%ld,bd=%lld)\n",event->event_time,event->data,event->bigdata);
612fb16552fSMaurice Kalinowski
613fb16552fSMaurice Kalinowski	if (fCurrentFile != 0)
614fb16552fSMaurice Kalinowski		return fCurrentFile->Seek(event->bigdata,SEEK_SET);
615fb16552fSMaurice Kalinowski	else
616fb16552fSMaurice Kalinowski		return B_ERROR;
617242094dbSshatty}
618242094dbSshatty
619fb16552fSMaurice Kalinowski
620242094dbSshattystatus_t AbstractFileInterfaceNode::HandleWarp(
621242094dbSshatty						const media_timed_event *event,
622242094dbSshatty						bigtime_t lateness,
623fb16552fSMaurice Kalinowski						bool realTimeEvent)
624242094dbSshatty{
625fb16552fSMaurice Kalinowski	CALLED();
626fb16552fSMaurice Kalinowski	return B_OK;
627242094dbSshatty}
628242094dbSshatty
629fb16552fSMaurice Kalinowski
630242094dbSshattystatus_t AbstractFileInterfaceNode::HandleStop(
631242094dbSshatty						const media_timed_event *event,
632242094dbSshatty						bigtime_t lateness,
633fb16552fSMaurice Kalinowski						bool realTimeEvent)
634242094dbSshatty{
635fb16552fSMaurice Kalinowski	CALLED();
636fb16552fSMaurice Kalinowski
637242094dbSshatty	// flush the queue so downstreamers don't get any more
638242094dbSshatty	EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
639fb16552fSMaurice Kalinowski	return B_OK;
640242094dbSshatty}
641242094dbSshatty
642fb16552fSMaurice Kalinowski
643242094dbSshattystatus_t AbstractFileInterfaceNode::HandleParameter(
644242094dbSshatty				const media_timed_event *event,
645242094dbSshatty				bigtime_t lateness,
646fb16552fSMaurice Kalinowski				bool realTimeEvent)
647242094dbSshatty{
648fb16552fSMaurice Kalinowski	CALLED();
649fb16552fSMaurice Kalinowski
650242094dbSshatty	status_t status = B_OK;
651fb16552fSMaurice Kalinowski
652242094dbSshatty	bool chunkSizeUpdated = false, bitRateUpdated = false, bufferPeriodUpdated = false;
653fb16552fSMaurice Kalinowski
654242094dbSshatty	size_t dataSize = size_t(event->data);
655981e4127Sshatty	int64 param = int64(event->bigdata);
656fb16552fSMaurice Kalinowski
657242094dbSshatty	switch (param) {
658242094dbSshatty		case DEFAULT_CHUNK_SIZE_PARAM:
659fb16552fSMaurice Kalinowski			PRINT("(DEFAULT_CHUNK_SIZE_PARAM,size=%ld",dataSize);
660242094dbSshatty			if (dataSize < sizeof(size_t)) {
661fb16552fSMaurice Kalinowski				PRINT("\��<- B_BAD_VALUE: %lld\n",param);
662242094dbSshatty				status = B_BAD_VALUE;
663242094dbSshatty			} else {
664242094dbSshatty				size_t newDefaultChunkSize = *((size_t*)event->user_data);
665fb16552fSMaurice Kalinowski				PRINT(",%ld)\n", newDefaultChunkSize);
666242094dbSshatty				// ignore non positive chunk sizes
667242094dbSshatty				// XXX: we may decide later that a 0 chunk size means ship the whole file in one chunk (!)
668242094dbSshatty				if ((newDefaultChunkSize > 0) && (newDefaultChunkSize != fDefaultChunkSizeParam)) {
669fb16552fSMaurice Kalinowski					PRINT("\tgot a new chunk size, old chunk size was %ld\n",fDefaultChunkSizeParam);
670242094dbSshatty					fDefaultChunkSizeParam = newDefaultChunkSize;
671242094dbSshatty					fDefaultChunkSizeParamChangeTime = TimeSource()->Now();
672242094dbSshatty					chunkSizeUpdated = true;
673242094dbSshatty					if (fLeastRecentlyUpdatedParameter == DEFAULT_CHUNK_SIZE_PARAM) {
674242094dbSshatty						// Okay we were the least recently updated parameter,
675242094dbSshatty						// but we just got an update so we are no longer that.
676242094dbSshatty						// Let's figure out who the new least recently updated
677242094dbSshatty						// parameter is.  We are going to prefer to compute the
678242094dbSshatty						// bit rate since you usually don't want to muck with
679242094dbSshatty						// the buffer period.  However, if you just set the bitrate
680242094dbSshatty						// then we are stuck with making the buffer period the new
681242094dbSshatty						// parameter to be computed.
682fb16552fSMaurice Kalinowski						if (fLastUpdatedParameter == DEFAULT_BIT_RATE_PARAM)
683242094dbSshatty							fLeastRecentlyUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM;
684fb16552fSMaurice Kalinowski						else
685242094dbSshatty							fLeastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM;
686242094dbSshatty					}
687242094dbSshatty					// we just got an update, so we are the new lastUpdatedParameter
688242094dbSshatty					fLastUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM;
689242094dbSshatty					// now we have to compute the new value for the leastRecentlyUpdatedParameter
690242094dbSshatty					// we use the chunk size change time to preserve "simultaneity" information
691242094dbSshatty					if (fLeastRecentlyUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) {
692242094dbSshatty						int64 value = int64(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam);
693242094dbSshatty						if (value > INT_MAX) {
694242094dbSshatty							// clamp to INT_MAX
695242094dbSshatty							fDefaultBufferPeriodParam = INT_MAX;
696242094dbSshatty							// recompute chunk size
697242094dbSshatty							fDefaultChunkSizeParam = size_t(1024/8000000*fDefaultBitRateParam*fDefaultBufferPeriodParam);
698242094dbSshatty						} else {
699242094dbSshatty							fDefaultBufferPeriodParam = MAX(1,value);
700242094dbSshatty						}
701242094dbSshatty						fDefaultBufferPeriodParamChangeTime = fDefaultChunkSizeParamChangeTime;
702242094dbSshatty						bufferPeriodUpdated = true;
703242094dbSshatty					} else { // must have been bit rate
704242094dbSshatty						fDefaultBitRateParam = MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam);
705242094dbSshatty						fDefaultBitRateParamChangeTime = fDefaultChunkSizeParamChangeTime;
706242094dbSshatty						bitRateUpdated = true;
707242094dbSshatty					}
708242094dbSshatty				}
709242094dbSshatty			}
710242094dbSshatty			break;
711242094dbSshatty		case DEFAULT_BIT_RATE_PARAM:
712fb16552fSMaurice Kalinowski			PRINT("(DEFAULT_BIT_RATE_PARAM,size=%ld",dataSize);
713242094dbSshatty			if (dataSize < sizeof(float)) {
714fb16552fSMaurice Kalinowski				PRINT("\t<- B_BAD_VALUE:lld\n",param);
715242094dbSshatty				status = B_BAD_VALUE;
716242094dbSshatty			} else {
717242094dbSshatty				float newDefaultBitRate = *((float*)event->user_data);
718fb16552fSMaurice Kalinowski				PRINT(",%f)\n",newDefaultBitRate);
719242094dbSshatty				// ignore non positive bitrates
720242094dbSshatty				if ((newDefaultBitRate > 0) && (newDefaultBitRate != fDefaultBitRateParam)) {
721fb16552fSMaurice Kalinowski					PRINT("\tgot a new bit rate, old bit rate was %ld\n",fDefaultBitRateParam);
722242094dbSshatty					fDefaultBitRateParam = newDefaultBitRate;
723242094dbSshatty					fDefaultBitRateParamChangeTime = TimeSource()->Now();
724242094dbSshatty					bitRateUpdated = true;
725242094dbSshatty					if (fLeastRecentlyUpdatedParameter == DEFAULT_BIT_RATE_PARAM) {
726242094dbSshatty						// Okay we were the least recently updated parameter,
727242094dbSshatty						// but we just got an update so we are no longer that.
728242094dbSshatty						// Let's figure out who the new least recently updated
729242094dbSshatty						// parameter is.  We are going to prefer to compute the
730242094dbSshatty						// chunk size since you usually don't want to muck with
731242094dbSshatty						// the buffer period.  However, if you just set the chunk size
732242094dbSshatty						// then we are stuck with making the buffer period the new
733242094dbSshatty						// parameter to be computed.
734242094dbSshatty						if (fLastUpdatedParameter == DEFAULT_CHUNK_SIZE_PARAM) {
735242094dbSshatty							fLeastRecentlyUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM;
736242094dbSshatty						} else {
737242094dbSshatty							fLeastRecentlyUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM;
738242094dbSshatty						}
739242094dbSshatty					}
740242094dbSshatty					// we just got an update, so we are the new lastUpdatedParameter
741242094dbSshatty					fLastUpdatedParameter = DEFAULT_BIT_RATE_PARAM;
742242094dbSshatty					// now we have to compute the new value for the leastRecentlyUpdatedParameter
743242094dbSshatty					// we use the bit rate change time to preserve "simultaneity" information
744242094dbSshatty					if (fLeastRecentlyUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) {
745fb16552fSMaurice Kalinowski						int64 value =
746fb16552fSMaurice Kalinowski								int64(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam);
747242094dbSshatty						if (value > INT_MAX) {
748242094dbSshatty							// clamp to INT_MAX
749242094dbSshatty							fDefaultBufferPeriodParam = INT_MAX;
750242094dbSshatty							// recompute bit rate
751fb16552fSMaurice Kalinowski							fDefaultBitRateParam = MAX(0.001,
752fb16552fSMaurice Kalinowski										8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam);
753242094dbSshatty						} else {
754242094dbSshatty							fDefaultBufferPeriodParam = MAX(1,int32(value));
755242094dbSshatty						}
756242094dbSshatty						fDefaultBufferPeriodParamChangeTime = fDefaultBitRateParamChangeTime;
757242094dbSshatty						bufferPeriodUpdated = true;
758242094dbSshatty					} else { // must have been chunk size
759fb16552fSMaurice Kalinowski						int64 value =
760fb16552fSMaurice Kalinowski								int64(1024/8000000*fDefaultBitRateParam*fDefaultBufferPeriodParam);
761242094dbSshatty						if (value > INT_MAX) {
762242094dbSshatty							// clamp to INT_MAX
763242094dbSshatty							fDefaultChunkSizeParam = INT_MAX;
764242094dbSshatty							// recompute bit rate
765fb16552fSMaurice Kalinowski							fDefaultBitRateParam =
766fb16552fSMaurice Kalinowski									MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam);
767242094dbSshatty						} else {
768242094dbSshatty							fDefaultChunkSizeParam = MAX(1,int32(value));
769242094dbSshatty						}
770242094dbSshatty						fDefaultChunkSizeParamChangeTime = fDefaultBitRateParamChangeTime;
771242094dbSshatty						chunkSizeUpdated = true;
772242094dbSshatty					}
773242094dbSshatty				}
774242094dbSshatty			}
775242094dbSshatty			break;
776242094dbSshatty		case DEFAULT_BUFFER_PERIOD_PARAM:
777fb16552fSMaurice Kalinowski			PRINT("(DEFAULT_BUFFER_PERIOD_PARAM,size=%ld",dataSize);
778242094dbSshatty			if (dataSize < sizeof(int32)) {
779fb16552fSMaurice Kalinowski				PRINT("\t<- B_BAD_VALUE:%ld\n",param);
780242094dbSshatty				status = B_BAD_VALUE;
781242094dbSshatty			} else {
782242094dbSshatty				int32 newBufferPeriod = *((int32*)event->user_data);
783fb16552fSMaurice Kalinowski				PRINT(",%ld)\n",newBufferPeriod);
784242094dbSshatty				// ignore non positive buffer period
785242094dbSshatty				if ((newBufferPeriod > 0) && (newBufferPeriod != fDefaultBufferPeriodParam)) {
786fb16552fSMaurice Kalinowski					PRINT("\tgot a new buffer period, old buffer period was %ld\n",
787fb16552fSMaurice Kalinowski						  fDefaultBufferPeriodParam);
788242094dbSshatty					fDefaultBufferPeriodParam = newBufferPeriod;
789242094dbSshatty					fDefaultBufferPeriodParamChangeTime = TimeSource()->Now();
790242094dbSshatty					bufferPeriodUpdated = true;
791242094dbSshatty					if (fLastUpdatedParameter == DEFAULT_BUFFER_PERIOD_PARAM) {
792242094dbSshatty						// prefer to update bit rate, unless you just set it
793242094dbSshatty						if (fLastUpdatedParameter == DEFAULT_BIT_RATE_PARAM) {
794242094dbSshatty							fLeastRecentlyUpdatedParameter = DEFAULT_CHUNK_SIZE_PARAM;
795242094dbSshatty						} else {
796242094dbSshatty							fLeastRecentlyUpdatedParameter = DEFAULT_BIT_RATE_PARAM;
797242094dbSshatty						}
798242094dbSshatty					}
799242094dbSshatty					// we just got an update, so we are the new lastUpdatedParameter
800242094dbSshatty					fLastUpdatedParameter = DEFAULT_BUFFER_PERIOD_PARAM;
801242094dbSshatty					// now we have to compute the new value for the leastRecentlyUpdatedParameter
802242094dbSshatty					// we use the buffer period change time to preserve "simultaneity" information
803242094dbSshatty					if (fLeastRecentlyUpdatedParameter == DEFAULT_BIT_RATE_PARAM) {
804fb16552fSMaurice Kalinowski						fDefaultBitRateParam =
805fb16552fSMaurice Kalinowski								MAX(0.001,8000000/1024*fDefaultChunkSizeParam/fDefaultBufferPeriodParam);
806242094dbSshatty						fDefaultBitRateParamChangeTime = fDefaultBufferPeriodParamChangeTime;
807242094dbSshatty						bitRateUpdated = true;
808242094dbSshatty					} else { // must have been chunk size
809242094dbSshatty						int64 value = int64(1024/8000000*fDefaultBitRateParam*fDefaultBufferPeriodParam);
810242094dbSshatty						if (value > INT_MAX) {
811242094dbSshatty							// clamp to INT_MAX
812242094dbSshatty							fDefaultChunkSizeParam = INT_MAX;
813242094dbSshatty							// recompute buffer period
814fb16552fSMaurice Kalinowski							fDefaultBufferPeriodParam =
815fb16552fSMaurice Kalinowski									size_t(8000000/1024*fDefaultChunkSizeParam/fDefaultBitRateParam);
816242094dbSshatty						} else {
817242094dbSshatty							fDefaultChunkSizeParam = MAX(1,int32(value));
818242094dbSshatty						}
819242094dbSshatty						fDefaultChunkSizeParamChangeTime = fDefaultBufferPeriodParamChangeTime;
820242094dbSshatty						chunkSizeUpdated = true;
821242094dbSshatty					}
822242094dbSshatty				}
823242094dbSshatty			}
824242094dbSshatty			break;
825242094dbSshatty		default:
826fb16552fSMaurice Kalinowski			PRINT("AbstractFileInterfaceNode::HandleParameter called with unknown param id (%ld)\n",param);
827242094dbSshatty			status = B_ERROR;
828242094dbSshatty	}
829242094dbSshatty	// send updates out for all the parameters that changed
830242094dbSshatty	// in every case this should be two updates. (if I have not made an error :-) )
831242094dbSshatty	if (chunkSizeUpdated) {
832fb16552fSMaurice Kalinowski		PRINT("\tchunk size parameter updated\n");
833242094dbSshatty		BroadcastNewParameterValue(fDefaultChunkSizeParamChangeTime,
834242094dbSshatty								   DEFAULT_CHUNK_SIZE_PARAM,
835242094dbSshatty								   &fDefaultChunkSizeParam,
836242094dbSshatty								   sizeof(fDefaultChunkSizeParam));
837242094dbSshatty	}
838242094dbSshatty	if (bitRateUpdated) {
839fb16552fSMaurice Kalinowski		PRINT("\tbit rate parameter updated\n");
840242094dbSshatty		BroadcastNewParameterValue(fDefaultBitRateParamChangeTime,
841242094dbSshatty								   DEFAULT_BIT_RATE_PARAM,
842242094dbSshatty								   &fDefaultBitRateParam,
843242094dbSshatty								   sizeof(fDefaultBitRateParam));
844242094dbSshatty	}
845242094dbSshatty	if (bufferPeriodUpdated) {
846fb16552fSMaurice Kalinowski		PRINT("\tbuffer period parameter updated\n");
847242094dbSshatty		BroadcastNewParameterValue(fDefaultBufferPeriodParamChangeTime,
848242094dbSshatty								   DEFAULT_BUFFER_PERIOD_PARAM,
849242094dbSshatty								   &fDefaultBufferPeriodParam,
850242094dbSshatty								   sizeof(fDefaultBufferPeriodParam));
851242094dbSshatty	}
852242094dbSshatty	return status;
853242094dbSshatty}
854242094dbSshatty
855fb16552fSMaurice Kalinowski
856242094dbSshatty// -------------------------------------------------------- //
857242094dbSshatty// AbstractFileInterfaceNode specific functions
858242094dbSshatty// -------------------------------------------------------- //
8592a6deaf6Sshattyvoid AbstractFileInterfaceNode::GetFlavor(flavor_info * info, int32 id)
860242094dbSshatty{
861fb16552fSMaurice Kalinowski	CALLED();
862fb16552fSMaurice Kalinowski
863fb16552fSMaurice Kalinowski	if (info == 0)
86445ed7b19Sshatty		return;
865fb16552fSMaurice Kalinowski
866fb16552fSMaurice Kalinowski	info->name = strdup("AbstractFileInterfaceNode");
867fb16552fSMaurice Kalinowski	info->info = strdup("A AbstractFileInterfaceNode node handles a file.");
8682a6deaf6Sshatty	info->kinds = B_FILE_INTERFACE | B_CONTROLLABLE;
8692a6deaf6Sshatty	info->flavor_flags = B_FLAVOR_IS_LOCAL;
8702a6deaf6Sshatty	info->possible_count = INT_MAX;
8712a6deaf6Sshatty	info->in_format_count = 0; // no inputs
8722a6deaf6Sshatty	info->in_formats = 0;
8732a6deaf6Sshatty	info->out_format_count = 0; // no outputs
8742a6deaf6Sshatty	info->out_formats = 0;
8752a6deaf6Sshatty	info->internal_id = id;
8762a6deaf6Sshatty	return;
877242094dbSshatty}
878242094dbSshatty
879fb16552fSMaurice Kalinowski
88045ed7b19Sshattyvoid AbstractFileInterfaceNode::GetFormat(media_format * outFormat)
881242094dbSshatty{
882fb16552fSMaurice Kalinowski	CALLED();
883fb16552fSMaurice Kalinowski
884fb16552fSMaurice Kalinowski	if (outFormat == 0)
88545ed7b19Sshatty		return;
886fb16552fSMaurice Kalinowski
88745ed7b19Sshatty	outFormat->type = B_MEDIA_MULTISTREAM;
88845ed7b19Sshatty	outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
88945ed7b19Sshatty	outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
89045ed7b19Sshatty	outFormat->u.multistream = media_multistream_format::wildcard;
891242094dbSshatty}
892242094dbSshatty
893fb16552fSMaurice Kalinowski
89445ed7b19Sshattyvoid AbstractFileInterfaceNode::GetFileFormat(media_file_format * outFileFormat)
895242094dbSshatty{
896fb16552fSMaurice Kalinowski	CALLED();
897fb16552fSMaurice Kalinowski
898fb16552fSMaurice Kalinowski	if (outFileFormat == 0)
89945ed7b19Sshatty		return;
900fb16552fSMaurice Kalinowski
90145ed7b19Sshatty	outFileFormat->capabilities =
90245ed7b19Sshatty			  media_file_format::B_PERFECTLY_SEEKABLE
90345ed7b19Sshatty			| media_file_format::B_IMPERFECTLY_SEEKABLE
90445ed7b19Sshatty			| media_file_format::B_KNOWS_ANYTHING;
90545ed7b19Sshatty	/* I don't know what to initialize this to. (or if I should) */
90645ed7b19Sshatty	// format.id =
90745ed7b19Sshatty	outFileFormat->family = B_ANY_FORMAT_FAMILY;
90845ed7b19Sshatty	outFileFormat->version = 100;
90945ed7b19Sshatty	// see media_file_format in <MediaDefs.h> for limits
91045ed7b19Sshatty	strncpy(outFileFormat->mime_type,"",63);
91145ed7b19Sshatty	outFileFormat->mime_type[63]='\0';
91245ed7b19Sshatty	strncpy(outFileFormat->pretty_name,"any media file format",63);
91345ed7b19Sshatty	outFileFormat->pretty_name[63]='\0';
91445ed7b19Sshatty	strncpy(outFileFormat->short_name,"any",31);
91545ed7b19Sshatty	outFileFormat->short_name[31]='\0';
91645ed7b19Sshatty	strncpy(outFileFormat->file_extension,"",7);
91745ed7b19Sshatty	outFileFormat->file_extension[7]='\0';
918242094dbSshatty}
919242094dbSshatty
920242094dbSshatty
921fb16552fSMaurice Kalinowski// protected:
922242094dbSshatty// Here we make some guesses based on the file's mime type.
923242094dbSshatty// We don't have enough information to add any other requirements.
924242094dbSshatty// This function doesn't complain if you have already decided you want
925242094dbSshatty// the stream to be considered a different one. (so you can say that you
926242094dbSshatty// want to read that mpeg file as avi if you are so nutty.)
927242094dbSshatty//
928242094dbSshattystatus_t AbstractFileInterfaceNode::AddRequirements(media_format * format)
929242094dbSshatty{
930242094dbSshatty	if (strcmp("video/x-msvideo",f_current_mime_type) == 0) {
931242094dbSshatty		if (format->u.multistream.format == media_multistream_format::wildcard.format) {
932242094dbSshatty			format->u.multistream.format = media_multistream_format::B_AVI;
933242094dbSshatty		}
934242094dbSshatty	} else
935242094dbSshatty	if (strcmp("video/mpeg",f_current_mime_type) == 0) {
936242094dbSshatty		if (format->u.multistream.format == media_multistream_format::wildcard.format) {
937242094dbSshatty			format->u.multistream.format = media_multistream_format::B_MPEG1;
938242094dbSshatty		}
939242094dbSshatty	} else
940242094dbSshatty	if (strcmp("video/quicktime",f_current_mime_type) == 0) {
941242094dbSshatty		if (format->u.multistream.format == media_multistream_format::wildcard.format) {
942242094dbSshatty			format->u.multistream.format = media_multistream_format::B_QUICKTIME;
943242094dbSshatty		}
944242094dbSshatty	} else
945242094dbSshatty	if (strcmp("audio/x-mpeg",f_current_mime_type) == 0) {
946242094dbSshatty		if (format->u.multistream.format == media_multistream_format::wildcard.format) {
947242094dbSshatty			format->u.multistream.format = media_multistream_format::B_MPEG1;
948242094dbSshatty		}
949242094dbSshatty	}
950242094dbSshatty	return B_OK;
951242094dbSshatty}
952242094dbSshatty
953fb16552fSMaurice Kalinowski
954242094dbSshatty// We need some sort of bit rate and chunk size, so if the other guy
955242094dbSshatty// didn't care, we'll use our own defaults.
956242094dbSshattystatus_t AbstractFileInterfaceNode::ResolveWildcards(media_format * format)
957242094dbSshatty{
958fb16552fSMaurice Kalinowski	CALLED();
959fb16552fSMaurice Kalinowski	// There isn't an unknown format. hmph.
960fb16552fSMaurice Kalinowski	//	if (format->u.multistream.format == media_multistream_format::wildcard.format) {
961fb16552fSMaurice Kalinowski	//		format->u.multistream.format = media_multistream_format::B_UNKNOWN;
962fb16552fSMaurice Kalinowski	//	}
963242094dbSshatty	if (format->u.multistream.max_bit_rate == media_multistream_format::wildcard.max_bit_rate) {
964242094dbSshatty		format->u.multistream.max_bit_rate = fDefaultBitRateParam;
965242094dbSshatty	}
966242094dbSshatty	if (format->u.multistream.max_chunk_size == media_multistream_format::wildcard.max_chunk_size) {
967242094dbSshatty		format->u.multistream.max_chunk_size = fDefaultChunkSizeParam;
968242094dbSshatty	}
969242094dbSshatty	if (format->u.multistream.avg_bit_rate == media_multistream_format::wildcard.avg_bit_rate) {
970242094dbSshatty		format->u.multistream.avg_bit_rate = fDefaultBitRateParam;
971242094dbSshatty	}
972242094dbSshatty	if (format->u.multistream.avg_chunk_size == media_multistream_format::wildcard.avg_chunk_size) {
973242094dbSshatty		format->u.multistream.avg_chunk_size = fDefaultChunkSizeParam;
974242094dbSshatty	}
975242094dbSshatty	return B_OK;
976242094dbSshatty}
977242094dbSshatty
978