1 // AbstractFileInterfaceNode.cpp
3 // Andrew Bachmann, 2002
5 // The AbstractFileInterfaceNode class implements
6 // the common functionality between MediaReader
8 #include "AbstractFileInterfaceNode.h"
12 #include <Controllable.h>
16 #include <FileInterface.h>
17 #include <MediaDefs.h>
18 #include <MediaEventLooper.h>
19 #include <MediaNode.h>
20 #include <TimeSource.h>
21 #include <ParameterWeb.h>
27 AbstractFileInterfaceNode::~AbstractFileInterfaceNode(void)
31 // Stop the BMediaEventLooper thread
33 if (fCurrentFile
!= 0)
38 AbstractFileInterfaceNode::AbstractFileInterfaceNode(
39 size_t defaultChunkSize
,
41 const flavor_info
* info
,
44 : BMediaNode("AbstractFileInterfaceNode"),
51 // keep our creator around for AddOn calls later
55 f_current_mime_type
[0] = '\0';
57 // initialize the parameters
58 if (defaultChunkSize
<= 0) {
59 fInitCheckStatus
= B_BAD_VALUE
;
63 fDefaultChunkSizeParam
= defaultChunkSize
;
64 fDefaultChunkSizeParamChangeTime
= 0;
65 if (defaultBitRate
<= 0) {
66 fInitCheckStatus
= B_BAD_VALUE
;
70 fDefaultBitRateParam
= defaultBitRate
;
71 fDefaultBitRateParamChangeTime
= 0;
72 // initialize parameter compute fields
73 fLeastRecentlyUpdatedParameter
= DEFAULT_BIT_RATE_PARAM
;
74 fLastUpdatedParameter
= DEFAULT_BUFFER_PERIOD_PARAM
;
75 // From the chunk size and bit rate we compute the buffer period.
76 int64 value
= int64(8000000/1024*fDefaultChunkSizeParam
/fDefaultBitRateParam
);
77 if ((value
<= 0) || (value
> INT_MAX
)) {
78 fInitCheckStatus
= B_BAD_VALUE
;
81 fDefaultBufferPeriodParam
= int32(value
);
82 fDefaultBufferPeriodParamChangeTime
= 0;
84 fInitCheckStatus
= B_OK
;
88 status_t
AbstractFileInterfaceNode::InitCheck(void) const
91 return fInitCheckStatus
;
95 status_t
AbstractFileInterfaceNode::GetConfigurationFor(
96 BMessage
* into_message
)
103 // -------------------------------------------------------- //
104 // implementation of BMediaNode
105 // -------------------------------------------------------- //
106 BMediaAddOn
* AbstractFileInterfaceNode::AddOn(
107 int32
* internal_id
) const
110 // BeBook says this only gets called if we were in an add-on.
112 // If we get a null pointer then we just won't write.
113 if (internal_id
!= 0)
120 void AbstractFileInterfaceNode::Start(
121 bigtime_t performance_time
)
123 PRINT("AbstractFileInterfaceNode::Start(pt=%lld)\n",performance_time
);
124 BMediaEventLooper::Start(performance_time
);
128 void AbstractFileInterfaceNode::Stop(
129 bigtime_t performance_time
,
132 PRINT("AbstractFileInterfaceNode::Stop(pt=%lld, im=%d)\n",
133 performance_time
, immediate
);
134 BMediaEventLooper::Stop(performance_time
,immediate
);
138 void AbstractFileInterfaceNode::Seek(
139 bigtime_t media_time
,
140 bigtime_t performance_time
)
142 PRINT("AbstractFileInterfaceNode::Seek(mt=%lld,pt=%lld)\n",
143 media_time
,performance_time
);
144 BMediaEventLooper::Seek(media_time
,performance_time
);
148 void AbstractFileInterfaceNode::SetRunMode(
151 PRINT("AbstractFileInterfaceNode::SetRunMode(%i)\n",mode
);
152 BMediaEventLooper::SetRunMode(mode
);
156 void AbstractFileInterfaceNode::TimeWarp(
157 bigtime_t at_real_time
,
158 bigtime_t to_performance_time
)
160 PRINT("AbstractFileInterfaceNode::TimeWarp(rt=%lld,pt=%lld)\n",
161 at_real_time
,to_performance_time
);
162 BMediaEventLooper::TimeWarp(at_real_time
,to_performance_time
);
166 void AbstractFileInterfaceNode::Preroll(void)
169 // XXX:Performance opportunity
170 BMediaNode::Preroll();
174 void AbstractFileInterfaceNode::SetTimeSource(
175 BTimeSource
* time_source
)
178 BMediaNode::SetTimeSource(time_source
);
182 status_t
AbstractFileInterfaceNode::HandleMessage(
189 status_t status
= B_OK
;
191 // no special messages for now
193 status
= BFileInterface::HandleMessage(message
,data
,size
);
194 if (status
== B_OK
) {
197 status
= BControllable::HandleMessage(message
, data
, size
);
200 status
= BMediaNode::HandleMessage(message
,data
,size
);
201 if (status
== B_OK
) {
204 BMediaNode::HandleBadMessage(message
,data
,size
);
212 status_t
AbstractFileInterfaceNode::RequestCompleted(
213 const media_request_info
& info
)
216 return BMediaNode::RequestCompleted(info
);
220 status_t
AbstractFileInterfaceNode::DeleteHook(
224 return BMediaEventLooper::DeleteHook(node
);
228 void AbstractFileInterfaceNode::NodeRegistered(void)
232 // set up our parameter web
233 SetParameterWeb(MakeParameterWeb());
235 // start the BMediaEventLooper thread
236 SetPriority(B_REAL_TIME_PRIORITY
);
241 status_t
AbstractFileInterfaceNode::GetNodeAttributes(
242 media_node_attribute
* outAttributes
,
246 return BMediaNode::GetNodeAttributes(outAttributes
,inMaxCount
);
250 status_t
AbstractFileInterfaceNode::AddTimer(
251 bigtime_t at_performance_time
,
255 return BMediaEventLooper::AddTimer(at_performance_time
,cookie
);
260 BParameterWeb
* AbstractFileInterfaceNode::MakeParameterWeb(void)
264 BParameterWeb
* web
= new BParameterWeb();
265 BParameterGroup
* mainGroup
= web
->MakeGroup("AbstractFileInterfaceNode Parameters");
267 // these three are related:
268 // DEFAULT_CHUNK_SIZE_PARAM =
269 // DEFAULT_BIT_RATE_PARAM / 1024 * DEFAULT_BUFFER_PERIOD_PARAM * 1000
270 BParameterGroup
* chunkSizeGroup
= mainGroup
->MakeGroup("Chunk Size Group");
271 BContinuousParameter
* chunkSizeParameter
272 = chunkSizeGroup
->MakeContinuousParameter(
273 DEFAULT_CHUNK_SIZE_PARAM
, B_MEDIA_MULTISTREAM
,
274 "Chunk Size", B_GAIN
, "bytes", 1024, 32*1024, 512);
275 chunkSizeParameter
->SetResponse(BContinuousParameter::B_LINEAR
,1,0);
276 chunkSizeParameter
->SetValue(&fDefaultChunkSizeParam
,sizeof(fDefaultChunkSizeParam
),0);
278 BParameterGroup
* bitRateGroup
= mainGroup
->MakeGroup("Bit Rate Group");
279 BContinuousParameter
* bitRateParameter
280 = bitRateGroup
->MakeContinuousParameter(
281 DEFAULT_BIT_RATE_PARAM
, B_MEDIA_MULTISTREAM
,
282 "Bit Rate", B_GAIN
, "kbits/sec", 1, 320000, 1);
283 bitRateParameter
->SetResponse(BContinuousParameter::B_LINEAR
,.001,0);
284 bitRateParameter
->SetValue(&fDefaultBitRateParam
,sizeof(fDefaultBitRateParam
),0);
286 BParameterGroup
* bufferPeriodGroup
= mainGroup
->MakeGroup("Buffer Period Group");
287 BContinuousParameter
* bufferPeriodParameter
288 = bufferPeriodGroup
->MakeContinuousParameter(
289 DEFAULT_BUFFER_PERIOD_PARAM
, B_MEDIA_MULTISTREAM
,
290 "Buffer Period", B_GAIN
, "ms", 1, 10000, 1);
291 bufferPeriodParameter
->SetResponse(BContinuousParameter::B_LINEAR
,1,0);
292 bufferPeriodParameter
->SetValue(&fDefaultBufferPeriodParam
,sizeof(fDefaultBufferPeriodParam
),0);
298 // -------------------------------------------------------- //
299 // implementation of BFileInterface
300 // -------------------------------------------------------- //
301 status_t
AbstractFileInterfaceNode::GetNextFileFormat(
303 media_file_format
* out_format
)
307 // it's valid but they already got our 1 file format
309 PRINT("\t<- B_ERROR\n");
313 // so next time they won't get the same format again
315 GetFileFormat(out_format
);
320 void AbstractFileInterfaceNode::DisposeFileFormatCookie(
324 // nothing to do since our cookies are just integers
328 status_t
AbstractFileInterfaceNode::GetDuration(
329 bigtime_t
* out_time
)
333 PRINT("\t<- B_BAD_VALUE\n");
337 if (fCurrentFile
== 0) {
338 PRINT("\t<- B_NO_INIT\n");
342 return fCurrentFile
->GetSize(out_time
);
346 status_t
AbstractFileInterfaceNode::SniffRef(
347 const entry_ref
& file
,
348 char * out_mime_type
, /* 256 bytes */
352 return StaticSniffRef(file
,out_mime_type
,out_quality
);
356 status_t
AbstractFileInterfaceNode::SetRef(
357 const entry_ref
& file
,
360 bigtime_t
* out_time
)
365 f_current_ref
= file
;
366 if (fCurrentFile
== 0) {
367 fCurrentFile
= new BFile(&f_current_ref
,(openMode
|(create
?B_CREATE_FILE
:0)));
368 status
= fCurrentFile
->InitCheck();
370 status
= fCurrentFile
->SetTo(&f_current_ref
,(openMode
|(create
?B_CREATE_FILE
:0)));
373 if (status
!= B_OK
) {
374 PRINT("\t<- failed BFile initialization\n");
378 // cache the mime type for later
379 fCurrentFile
->ReadAttr("BEOS:TYPE",0,0,f_current_mime_type
,B_MIME_TYPE_LENGTH
);
380 // compute the duration and return any error
381 return GetDuration(out_time
);
385 status_t
AbstractFileInterfaceNode::GetRef(
387 char * out_mime_type
)
391 if (fCurrentFile
== 0) {
392 PRINT("\t<- B_NO_INIT\n");
393 return B_NO_INIT
; // the input_ref isn't valid yet either
396 *out_ref
= f_current_ref
;
397 // they hopefully allocated enough space (no way to check :-/ )
398 strcpy(out_mime_type
,f_current_mime_type
);
403 // provided for BAbstractFileInterfaceNodeAddOn
404 status_t
AbstractFileInterfaceNode::StaticSniffRef(
405 const entry_ref
& file
,
406 char * out_mime_type
, /* 256 bytes */
412 status_t initCheck
= node
.InitCheck();
413 if (initCheck
!= B_OK
) {
414 PRINT("\t<- failed BNode::InitCheck()\n");
418 // they hopefully allocated enough room
419 node
.ReadAttr("BEOS:TYPE",0,0,out_mime_type
,B_MIME_TYPE_LENGTH
);
420 *out_quality
= 1.0; // we handle all files perfectly! we are so amazing!
425 // -------------------------------------------------------- //
426 // implementation for BControllable
427 // -------------------------------------------------------- //
428 const int32
AbstractFileInterfaceNode::DEFAULT_CHUNK_SIZE_PARAM
= 1;
429 const int32
AbstractFileInterfaceNode::DEFAULT_BIT_RATE_PARAM
= 2;
430 const int32
AbstractFileInterfaceNode::DEFAULT_BUFFER_PERIOD_PARAM
= 3;
433 status_t
AbstractFileInterfaceNode::GetParameterValue(
435 bigtime_t
* last_change
,
442 case DEFAULT_CHUNK_SIZE_PARAM
:
443 if (*ioSize
< sizeof(size_t)) {
444 return B_ERROR
; // not enough room
446 *last_change
= fDefaultChunkSizeParamChangeTime
;
447 *((size_t*)value
) = fDefaultChunkSizeParam
;
448 *ioSize
= sizeof(size_t);
451 case DEFAULT_BIT_RATE_PARAM
:
452 if (*ioSize
< sizeof(float)) {
453 return B_ERROR
; // not enough room
455 *last_change
= fDefaultBitRateParamChangeTime
;
456 *((float*)value
) = fDefaultBitRateParam
;
457 *ioSize
= sizeof(float);
460 case DEFAULT_BUFFER_PERIOD_PARAM
:
461 if (*ioSize
< sizeof(int32
)) {
462 return B_ERROR
; // not enough room
464 *last_change
= fDefaultBufferPeriodParamChangeTime
;
465 *((int32
*)value
) = fDefaultBufferPeriodParam
;
466 *ioSize
= sizeof(int32
);
470 PRINT("AbstractFileInterfaceNode::GetParameterValue unknown id (%ld)\n",id
);
478 void AbstractFileInterfaceNode::SetParameterValue(
484 PRINT("AbstractFileInterfaceNode::SetParameterValue(id=%ld,when=%lld,size=%ld)\n",id
,when
,int32(size
));
487 case DEFAULT_CHUNK_SIZE_PARAM
:
488 case DEFAULT_BIT_RATE_PARAM
:
489 case DEFAULT_BUFFER_PERIOD_PARAM
:
491 media_timed_event
event(when
, BTimedEventQueue::B_PARAMETER
,
492 NULL
, BTimedEventQueue::B_NO_CLEANUP
,
493 size
, id
, (char*) value
, size
);
494 EventQueue()->AddEvent(event
);
499 PRINT("AbstractFileInterfaceNode::SetParameterValue unknown id (%ld)\n",id
);
505 // the default implementation should call the add-on main()
506 status_t
AbstractFileInterfaceNode::StartControlPanel(
507 BMessenger
* out_messenger
)
510 return BControllable::StartControlPanel(out_messenger
);
514 // -------------------------------------------------------- //
515 // implementation for BMediaEventLooper
516 // -------------------------------------------------------- //
517 void AbstractFileInterfaceNode::HandleEvent(
518 const media_timed_event
*event
,
523 switch (event
->type
) {
524 case BTimedEventQueue::B_START
:
525 HandleStart(event
,lateness
,realTimeEvent
);
527 case BTimedEventQueue::B_SEEK
:
528 HandleSeek(event
,lateness
,realTimeEvent
);
530 case BTimedEventQueue::B_WARP
:
531 HandleWarp(event
,lateness
,realTimeEvent
);
533 case BTimedEventQueue::B_STOP
:
534 HandleStop(event
,lateness
,realTimeEvent
);
536 case BTimedEventQueue::B_HANDLE_BUFFER
:
537 if (RunState() == BMediaEventLooper::B_STARTED
) {
538 HandleBuffer(event
,lateness
,realTimeEvent
);
541 case BTimedEventQueue::B_DATA_STATUS
:
542 HandleDataStatus(event
,lateness
,realTimeEvent
);
544 case BTimedEventQueue::B_PARAMETER
:
545 HandleParameter(event
,lateness
,realTimeEvent
);
548 PRINT(" unknown event type: %ld\n",event
->type
);
554 /* override to clean up custom events you have added to your queue */
555 void AbstractFileInterfaceNode::CleanUpEvent(
556 const media_timed_event
*event
)
558 BMediaEventLooper::CleanUpEvent(event
);
562 /* called from Offline mode to determine the current time of the node */
563 /* update your internal information whenever it changes */
564 bigtime_t
AbstractFileInterfaceNode::OfflineTime()
567 return BMediaEventLooper::OfflineTime();
568 // XXX: do something else?
569 // if (inputFile == 0) {
572 // return inputFile->Position();
577 /* override only if you know what you are doing! */
578 /* otherwise much badness could occur */
579 /* the actual control loop function: */
580 /* waits for messages, Pops events off the queue and calls DispatchEvent */
581 void AbstractFileInterfaceNode::ControlLoop() {
582 BMediaEventLooper::ControlLoop();
587 status_t
AbstractFileInterfaceNode::HandleStart(
588 const media_timed_event
*event
,
594 if (RunState() != B_STARTED
) {
595 // XXX: Either use the following line or the lines that are not commented.
596 // There doesn't seem to be a practical difference that i can tell.
597 // HandleBuffer(event,lateness,realTimeEvent);
598 media_timed_event
firstBufferEvent(event
->event_time
, BTimedEventQueue::B_HANDLE_BUFFER
);
599 HandleEvent(&firstBufferEvent
, 0, false);
600 EventQueue()->AddEvent(firstBufferEvent
);
606 status_t
AbstractFileInterfaceNode::HandleSeek(
607 const media_timed_event
*event
,
611 PRINT("AbstractFileInterfaceNode::HandleSeek(t=%lld,d=%ld,bd=%lld)\n",event
->event_time
,event
->data
,event
->bigdata
);
613 if (fCurrentFile
!= 0)
614 return fCurrentFile
->Seek(event
->bigdata
,SEEK_SET
);
620 status_t
AbstractFileInterfaceNode::HandleWarp(
621 const media_timed_event
*event
,
630 status_t
AbstractFileInterfaceNode::HandleStop(
631 const media_timed_event
*event
,
637 // flush the queue so downstreamers don't get any more
638 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS
, true, BTimedEventQueue::B_HANDLE_BUFFER
);
643 status_t
AbstractFileInterfaceNode::HandleParameter(
644 const media_timed_event
*event
,
650 status_t status
= B_OK
;
652 bool chunkSizeUpdated
= false, bitRateUpdated
= false, bufferPeriodUpdated
= false;
654 size_t dataSize
= size_t(event
->data
);
655 int64 param
= int64(event
->bigdata
);
658 case DEFAULT_CHUNK_SIZE_PARAM
:
659 PRINT("(DEFAULT_CHUNK_SIZE_PARAM,size=%ld",dataSize
);
660 if (dataSize
< sizeof(size_t)) {
661 PRINT("\ŧ<- B_BAD_VALUE: %lld\n",param
);
662 status
= B_BAD_VALUE
;
664 size_t newDefaultChunkSize
= *((size_t*)event
->user_data
);
665 PRINT(",%ld)\n", newDefaultChunkSize
);
666 // ignore non positive chunk sizes
667 // XXX: we may decide later that a 0 chunk size means ship the whole file in one chunk (!)
668 if ((newDefaultChunkSize
> 0) && (newDefaultChunkSize
!= fDefaultChunkSizeParam
)) {
669 PRINT("\tgot a new chunk size, old chunk size was %ld\n",fDefaultChunkSizeParam
);
670 fDefaultChunkSizeParam
= newDefaultChunkSize
;
671 fDefaultChunkSizeParamChangeTime
= TimeSource()->Now();
672 chunkSizeUpdated
= true;
673 if (fLeastRecentlyUpdatedParameter
== DEFAULT_CHUNK_SIZE_PARAM
) {
674 // Okay we were the least recently updated parameter,
675 // but we just got an update so we are no longer that.
676 // Let's figure out who the new least recently updated
677 // parameter is. We are going to prefer to compute the
678 // bit rate since you usually don't want to muck with
679 // the buffer period. However, if you just set the bitrate
680 // then we are stuck with making the buffer period the new
681 // parameter to be computed.
682 if (fLastUpdatedParameter
== DEFAULT_BIT_RATE_PARAM
)
683 fLeastRecentlyUpdatedParameter
= DEFAULT_BUFFER_PERIOD_PARAM
;
685 fLeastRecentlyUpdatedParameter
= DEFAULT_BIT_RATE_PARAM
;
687 // we just got an update, so we are the new lastUpdatedParameter
688 fLastUpdatedParameter
= DEFAULT_CHUNK_SIZE_PARAM
;
689 // now we have to compute the new value for the leastRecentlyUpdatedParameter
690 // we use the chunk size change time to preserve "simultaneity" information
691 if (fLeastRecentlyUpdatedParameter
== DEFAULT_BUFFER_PERIOD_PARAM
) {
692 int64 value
= int64(8000000/1024*fDefaultChunkSizeParam
/fDefaultBitRateParam
);
693 if (value
> INT_MAX
) {
695 fDefaultBufferPeriodParam
= INT_MAX
;
696 // recompute chunk size
697 fDefaultChunkSizeParam
= size_t(1024/8000000*fDefaultBitRateParam
*fDefaultBufferPeriodParam
);
699 fDefaultBufferPeriodParam
= MAX(1,value
);
701 fDefaultBufferPeriodParamChangeTime
= fDefaultChunkSizeParamChangeTime
;
702 bufferPeriodUpdated
= true;
703 } else { // must have been bit rate
704 fDefaultBitRateParam
= MAX(0.001,8000000/1024*fDefaultChunkSizeParam
/fDefaultBufferPeriodParam
);
705 fDefaultBitRateParamChangeTime
= fDefaultChunkSizeParamChangeTime
;
706 bitRateUpdated
= true;
711 case DEFAULT_BIT_RATE_PARAM
:
712 PRINT("(DEFAULT_BIT_RATE_PARAM,size=%ld",dataSize
);
713 if (dataSize
< sizeof(float)) {
714 PRINT("\t<- B_BAD_VALUE:lld\n",param
);
715 status
= B_BAD_VALUE
;
717 float newDefaultBitRate
= *((float*)event
->user_data
);
718 PRINT(",%f)\n",newDefaultBitRate
);
719 // ignore non positive bitrates
720 if ((newDefaultBitRate
> 0) && (newDefaultBitRate
!= fDefaultBitRateParam
)) {
721 PRINT("\tgot a new bit rate, old bit rate was %ld\n",fDefaultBitRateParam
);
722 fDefaultBitRateParam
= newDefaultBitRate
;
723 fDefaultBitRateParamChangeTime
= TimeSource()->Now();
724 bitRateUpdated
= true;
725 if (fLeastRecentlyUpdatedParameter
== DEFAULT_BIT_RATE_PARAM
) {
726 // Okay we were the least recently updated parameter,
727 // but we just got an update so we are no longer that.
728 // Let's figure out who the new least recently updated
729 // parameter is. We are going to prefer to compute the
730 // chunk size since you usually don't want to muck with
731 // the buffer period. However, if you just set the chunk size
732 // then we are stuck with making the buffer period the new
733 // parameter to be computed.
734 if (fLastUpdatedParameter
== DEFAULT_CHUNK_SIZE_PARAM
) {
735 fLeastRecentlyUpdatedParameter
= DEFAULT_BUFFER_PERIOD_PARAM
;
737 fLeastRecentlyUpdatedParameter
= DEFAULT_CHUNK_SIZE_PARAM
;
740 // we just got an update, so we are the new lastUpdatedParameter
741 fLastUpdatedParameter
= DEFAULT_BIT_RATE_PARAM
;
742 // now we have to compute the new value for the leastRecentlyUpdatedParameter
743 // we use the bit rate change time to preserve "simultaneity" information
744 if (fLeastRecentlyUpdatedParameter
== DEFAULT_BUFFER_PERIOD_PARAM
) {
746 int64(8000000/1024*fDefaultChunkSizeParam
/fDefaultBitRateParam
);
747 if (value
> INT_MAX
) {
749 fDefaultBufferPeriodParam
= INT_MAX
;
750 // recompute bit rate
751 fDefaultBitRateParam
= MAX(0.001,
752 8000000/1024*fDefaultChunkSizeParam
/fDefaultBufferPeriodParam
);
754 fDefaultBufferPeriodParam
= MAX(1,int32(value
));
756 fDefaultBufferPeriodParamChangeTime
= fDefaultBitRateParamChangeTime
;
757 bufferPeriodUpdated
= true;
758 } else { // must have been chunk size
760 int64(1024/8000000*fDefaultBitRateParam
*fDefaultBufferPeriodParam
);
761 if (value
> INT_MAX
) {
763 fDefaultChunkSizeParam
= INT_MAX
;
764 // recompute bit rate
765 fDefaultBitRateParam
=
766 MAX(0.001,8000000/1024*fDefaultChunkSizeParam
/fDefaultBufferPeriodParam
);
768 fDefaultChunkSizeParam
= MAX(1,int32(value
));
770 fDefaultChunkSizeParamChangeTime
= fDefaultBitRateParamChangeTime
;
771 chunkSizeUpdated
= true;
776 case DEFAULT_BUFFER_PERIOD_PARAM
:
777 PRINT("(DEFAULT_BUFFER_PERIOD_PARAM,size=%ld",dataSize
);
778 if (dataSize
< sizeof(int32
)) {
779 PRINT("\t<- B_BAD_VALUE:%ld\n",param
);
780 status
= B_BAD_VALUE
;
782 int32 newBufferPeriod
= *((int32
*)event
->user_data
);
783 PRINT(",%ld)\n",newBufferPeriod
);
784 // ignore non positive buffer period
785 if ((newBufferPeriod
> 0) && (newBufferPeriod
!= fDefaultBufferPeriodParam
)) {
786 PRINT("\tgot a new buffer period, old buffer period was %ld\n",
787 fDefaultBufferPeriodParam
);
788 fDefaultBufferPeriodParam
= newBufferPeriod
;
789 fDefaultBufferPeriodParamChangeTime
= TimeSource()->Now();
790 bufferPeriodUpdated
= true;
791 if (fLastUpdatedParameter
== DEFAULT_BUFFER_PERIOD_PARAM
) {
792 // prefer to update bit rate, unless you just set it
793 if (fLastUpdatedParameter
== DEFAULT_BIT_RATE_PARAM
) {
794 fLeastRecentlyUpdatedParameter
= DEFAULT_CHUNK_SIZE_PARAM
;
796 fLeastRecentlyUpdatedParameter
= DEFAULT_BIT_RATE_PARAM
;
799 // we just got an update, so we are the new lastUpdatedParameter
800 fLastUpdatedParameter
= DEFAULT_BUFFER_PERIOD_PARAM
;
801 // now we have to compute the new value for the leastRecentlyUpdatedParameter
802 // we use the buffer period change time to preserve "simultaneity" information
803 if (fLeastRecentlyUpdatedParameter
== DEFAULT_BIT_RATE_PARAM
) {
804 fDefaultBitRateParam
=
805 MAX(0.001,8000000/1024*fDefaultChunkSizeParam
/fDefaultBufferPeriodParam
);
806 fDefaultBitRateParamChangeTime
= fDefaultBufferPeriodParamChangeTime
;
807 bitRateUpdated
= true;
808 } else { // must have been chunk size
809 int64 value
= int64(1024/8000000*fDefaultBitRateParam
*fDefaultBufferPeriodParam
);
810 if (value
> INT_MAX
) {
812 fDefaultChunkSizeParam
= INT_MAX
;
813 // recompute buffer period
814 fDefaultBufferPeriodParam
=
815 size_t(8000000/1024*fDefaultChunkSizeParam
/fDefaultBitRateParam
);
817 fDefaultChunkSizeParam
= MAX(1,int32(value
));
819 fDefaultChunkSizeParamChangeTime
= fDefaultBufferPeriodParamChangeTime
;
820 chunkSizeUpdated
= true;
826 PRINT("AbstractFileInterfaceNode::HandleParameter called with unknown param id (%ld)\n",param
);
829 // send updates out for all the parameters that changed
830 // in every case this should be two updates. (if I have not made an error :-) )
831 if (chunkSizeUpdated
) {
832 PRINT("\tchunk size parameter updated\n");
833 BroadcastNewParameterValue(fDefaultChunkSizeParamChangeTime
,
834 DEFAULT_CHUNK_SIZE_PARAM
,
835 &fDefaultChunkSizeParam
,
836 sizeof(fDefaultChunkSizeParam
));
838 if (bitRateUpdated
) {
839 PRINT("\tbit rate parameter updated\n");
840 BroadcastNewParameterValue(fDefaultBitRateParamChangeTime
,
841 DEFAULT_BIT_RATE_PARAM
,
842 &fDefaultBitRateParam
,
843 sizeof(fDefaultBitRateParam
));
845 if (bufferPeriodUpdated
) {
846 PRINT("\tbuffer period parameter updated\n");
847 BroadcastNewParameterValue(fDefaultBufferPeriodParamChangeTime
,
848 DEFAULT_BUFFER_PERIOD_PARAM
,
849 &fDefaultBufferPeriodParam
,
850 sizeof(fDefaultBufferPeriodParam
));
856 // -------------------------------------------------------- //
857 // AbstractFileInterfaceNode specific functions
858 // -------------------------------------------------------- //
859 void AbstractFileInterfaceNode::GetFlavor(flavor_info
* info
, int32 id
)
866 info
->name
= strdup("AbstractFileInterfaceNode");
867 info
->info
= strdup("A AbstractFileInterfaceNode node handles a file.");
868 info
->kinds
= B_FILE_INTERFACE
| B_CONTROLLABLE
;
869 info
->flavor_flags
= B_FLAVOR_IS_LOCAL
;
870 info
->possible_count
= INT_MAX
;
871 info
->in_format_count
= 0; // no inputs
872 info
->in_formats
= 0;
873 info
->out_format_count
= 0; // no outputs
874 info
->out_formats
= 0;
875 info
->internal_id
= id
;
880 void AbstractFileInterfaceNode::GetFormat(media_format
* outFormat
)
887 outFormat
->type
= B_MEDIA_MULTISTREAM
;
888 outFormat
->require_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
889 outFormat
->deny_flags
= B_MEDIA_MAUI_UNDEFINED_FLAGS
;
890 outFormat
->u
.multistream
= media_multistream_format::wildcard
;
894 void AbstractFileInterfaceNode::GetFileFormat(media_file_format
* outFileFormat
)
898 if (outFileFormat
== 0)
901 outFileFormat
->capabilities
=
902 media_file_format::B_PERFECTLY_SEEKABLE
903 | media_file_format::B_IMPERFECTLY_SEEKABLE
904 | media_file_format::B_KNOWS_ANYTHING
;
905 /* I don't know what to initialize this to. (or if I should) */
907 outFileFormat
->family
= B_ANY_FORMAT_FAMILY
;
908 outFileFormat
->version
= 100;
909 // see media_file_format in <MediaDefs.h> for limits
910 strncpy(outFileFormat
->mime_type
,"",63);
911 outFileFormat
->mime_type
[63]='\0';
912 strncpy(outFileFormat
->pretty_name
,"any media file format",63);
913 outFileFormat
->pretty_name
[63]='\0';
914 strncpy(outFileFormat
->short_name
,"any",31);
915 outFileFormat
->short_name
[31]='\0';
916 strncpy(outFileFormat
->file_extension
,"",7);
917 outFileFormat
->file_extension
[7]='\0';
922 // Here we make some guesses based on the file's mime type.
923 // We don't have enough information to add any other requirements.
924 // This function doesn't complain if you have already decided you want
925 // the stream to be considered a different one. (so you can say that you
926 // want to read that mpeg file as avi if you are so nutty.)
928 status_t
AbstractFileInterfaceNode::AddRequirements(media_format
* format
)
930 if (strcmp("video/x-msvideo",f_current_mime_type
) == 0) {
931 if (format
->u
.multistream
.format
== media_multistream_format::wildcard
.format
) {
932 format
->u
.multistream
.format
= media_multistream_format::B_AVI
;
935 if (strcmp("video/mpeg",f_current_mime_type
) == 0) {
936 if (format
->u
.multistream
.format
== media_multistream_format::wildcard
.format
) {
937 format
->u
.multistream
.format
= media_multistream_format::B_MPEG1
;
940 if (strcmp("video/quicktime",f_current_mime_type
) == 0) {
941 if (format
->u
.multistream
.format
== media_multistream_format::wildcard
.format
) {
942 format
->u
.multistream
.format
= media_multistream_format::B_QUICKTIME
;
945 if (strcmp("audio/x-mpeg",f_current_mime_type
) == 0) {
946 if (format
->u
.multistream
.format
== media_multistream_format::wildcard
.format
) {
947 format
->u
.multistream
.format
= media_multistream_format::B_MPEG1
;
954 // We need some sort of bit rate and chunk size, so if the other guy
955 // didn't care, we'll use our own defaults.
956 status_t
AbstractFileInterfaceNode::ResolveWildcards(media_format
* format
)
959 // There isn't an unknown format. hmph.
960 // if (format->u.multistream.format == media_multistream_format::wildcard.format) {
961 // format->u.multistream.format = media_multistream_format::B_UNKNOWN;
963 if (format
->u
.multistream
.max_bit_rate
== media_multistream_format::wildcard
.max_bit_rate
) {
964 format
->u
.multistream
.max_bit_rate
= fDefaultBitRateParam
;
966 if (format
->u
.multistream
.max_chunk_size
== media_multistream_format::wildcard
.max_chunk_size
) {
967 format
->u
.multistream
.max_chunk_size
= fDefaultChunkSizeParam
;
969 if (format
->u
.multistream
.avg_bit_rate
== media_multistream_format::wildcard
.avg_bit_rate
) {
970 format
->u
.multistream
.avg_bit_rate
= fDefaultBitRateParam
;
972 if (format
->u
.multistream
.avg_chunk_size
== media_multistream_format::wildcard
.avg_chunk_size
) {
973 format
->u
.multistream
.avg_chunk_size
= fDefaultChunkSizeParam
;
979 // -------------------------------------------------------- //
981 // -------------------------------------------------------- //
982 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_0(void *) { return B_ERROR
; }
983 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_1(void *) { return B_ERROR
; }
984 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_2(void *) { return B_ERROR
; }
985 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_3(void *) { return B_ERROR
; }
986 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_4(void *) { return B_ERROR
; }
987 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_5(void *) { return B_ERROR
; }
988 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_6(void *) { return B_ERROR
; }
989 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_7(void *) { return B_ERROR
; }
990 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_8(void *) { return B_ERROR
; }
991 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_9(void *) { return B_ERROR
; }
992 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_10(void *) { return B_ERROR
; }
993 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_11(void *) { return B_ERROR
; }
994 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_12(void *) { return B_ERROR
; }
995 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_13(void *) { return B_ERROR
; }
996 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_14(void *) { return B_ERROR
; }
997 status_t
AbstractFileInterfaceNode::_Reserved_AbstractFileInterfaceNode_15(void *) { return B_ERROR
; }