xref: /haiku/src/apps/mediaplayer/Controller.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
1 /*
2  * Controller.cpp - Media Player for the Haiku Operating System
3  *
4  * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>
5  * Copyright (C) 2007-2008 Stephan Aßmus <superstippi@gmx.de> (MIT Ok)
6  * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  *
21  */
22 
23 
24 #include "Controller.h"
25 
26 #include <new>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include <Autolock.h>
31 #include <Bitmap.h>
32 #include <Debug.h>
33 #include <MediaFile.h>
34 #include <MediaTrack.h>
35 #include <Path.h>
36 #include <Window.h> // for debugging only
37 
38 #include "AutoDeleter.h"
39 #include "ControllerView.h"
40 #include "MainApp.h"
41 #include "PlaybackState.h"
42 #include "Settings.h"
43 #include "VideoView.h"
44 
45 // suppliers
46 #include "AudioTrackSupplier.h"
47 #include "MediaTrackAudioSupplier.h"
48 #include "MediaTrackVideoSupplier.h"
49 #include "ProxyAudioSupplier.h"
50 #include "ProxyVideoSupplier.h"
51 #include "VideoTrackSupplier.h"
52 
53 using std::nothrow;
54 
55 
56 void
57 HandleError(const char *text, status_t err)
58 {
59 	if (err != B_OK) {
60 		printf("%s. error 0x%08x (%s)\n",text, (int)err, strerror(err));
61 		fflush(NULL);
62 		exit(1);
63 	}
64 }
65 
66 
67 // #pragma mark - Controller::Listener
68 
69 
70 Controller::Listener::Listener() {}
71 Controller::Listener::~Listener() {}
72 void Controller::Listener::FileFinished() {}
73 void Controller::Listener::FileChanged(PlaylistItem* item, status_t result) {}
74 void Controller::Listener::VideoTrackChanged(int32) {}
75 void Controller::Listener::AudioTrackChanged(int32) {}
76 void Controller::Listener::VideoStatsChanged() {}
77 void Controller::Listener::AudioStatsChanged() {}
78 void Controller::Listener::PlaybackStateChanged(uint32) {}
79 void Controller::Listener::PositionChanged(float) {}
80 void Controller::Listener::VolumeChanged(float) {}
81 void Controller::Listener::MutedChanged(bool) {}
82 
83 
84 // #pragma mark - Controller
85 
86 
87 enum {
88 	MSG_SET_TO = 'stto'
89 };
90 
91 
92 Controller::Controller()
93 	:
94 	NodeManager(),
95 	fVideoView(NULL),
96 	fVolume(1.0),
97 	fActiveVolume(1.0),
98 	fMuted(false),
99 
100 	fItem(NULL),
101 	fMediaFile(NULL),
102 
103 	fVideoSupplier(new ProxyVideoSupplier()),
104 	fAudioSupplier(new ProxyAudioSupplier(this)),
105 	fVideoTrackSupplier(NULL),
106 	fAudioTrackSupplier(NULL),
107 
108 	fAudioTrackList(4),
109 	fVideoTrackList(2),
110 
111 	fPosition(0),
112 	fDuration(0),
113 	fVideoFrameRate(25.0),
114 	fSeekRequested(false),
115 
116 	fGlobalSettingsListener(this),
117 
118 	fListeners(4)
119 {
120 	Settings::Default()->AddListener(&fGlobalSettingsListener);
121 	_AdoptGlobalSettings();
122 
123 	fAutoplay = fAutoplaySetting;
124 }
125 
126 
127 Controller::~Controller()
128 {
129 	Settings::Default()->RemoveListener(&fGlobalSettingsListener);
130 	SetTo(NULL);
131 }
132 
133 
134 // #pragma mark - NodeManager interface
135 
136 
137 void
138 Controller::MessageReceived(BMessage* message)
139 {
140 	switch (message->what) {
141 		case MSG_OBJECT_CHANGED:
142 			// received from fGlobalSettingsListener
143 			// TODO: find out which object, if we ever watch more than
144 			// the global settings instance...
145 			_AdoptGlobalSettings();
146 			break;
147 
148 		case MSG_SET_TO:
149 		{
150 			PlaylistItem* item;
151 			if (message->FindPointer("item", (void**)&item) == B_OK) {
152 				PlaylistItemRef itemRef(item, true);
153 					// The reference was passed with the message.
154 				SetTo(itemRef);
155 			} else
156 				_NotifyFileChanged(NULL, B_BAD_VALUE);
157 
158 			break;
159 		}
160 
161 		default:
162 			NodeManager::MessageReceived(message);
163 	}
164 }
165 
166 
167 int64
168 Controller::Duration()
169 {
170 	// This should really be total frames (video frames at that)
171 	// TODO: It is not so nice that the MediaPlayer still measures
172 	// in video frames if only playing audio. Here for example, it will
173 	// return a duration of 0 if the audio clip happens to be shorter than
174 	// one video frame at 25 fps.
175 	return (int64)((double)fDuration * fVideoFrameRate / 1000000.0);
176 }
177 
178 
179 VideoTarget*
180 Controller::CreateVideoTarget()
181 {
182 	return fVideoView;
183 }
184 
185 
186 VideoSupplier*
187 Controller::CreateVideoSupplier()
188 {
189 	return fVideoSupplier;
190 }
191 
192 
193 AudioSupplier*
194 Controller::CreateAudioSupplier()
195 {
196 	return fAudioSupplier;
197 }
198 
199 
200 // #pragma mark -
201 
202 
203 status_t
204 Controller::SetToAsync(const PlaylistItemRef& item)
205 {
206 	PlaylistItemRef additionalReference(item);
207 
208 	BMessage message(MSG_SET_TO);
209 	status_t ret = message.AddPointer("item", item.Get());
210 	if (ret != B_OK)
211 		return ret;
212 
213 	ret = PostMessage(&message);
214 	if (ret != B_OK)
215 		return ret;
216 
217 	// The additional reference is now passed along with the message...
218 	additionalReference.Detach();
219 
220 	return B_OK;
221 }
222 
223 
224 status_t
225 Controller::SetTo(const PlaylistItemRef& item)
226 {
227 	BAutolock _(this);
228 
229 	if (fItem == item) {
230 		if (InitCheck() == B_OK) {
231 			if (fAutoplay) {
232 				SetPosition(0.0);
233 				StartPlaying(true);
234 			}
235 		}
236 		return B_OK;
237 	}
238 
239 	fItem = item;
240 
241 	fAudioSupplier->SetSupplier(NULL, fVideoFrameRate);
242 	fVideoSupplier->SetSupplier(NULL);
243 
244 	fAudioTrackList.MakeEmpty();
245 	fVideoTrackList.MakeEmpty();
246 
247 	ObjectDeleter<BMediaFile> oldMediaFileDeleter(fMediaFile);
248 		// BMediaFile destructor will call ReleaseAllTracks()
249 	fMediaFile = NULL;
250 
251 	// Do not delete the supplier chain until after we called
252 	// NodeManager::Init() to setup a new media node chain
253 	ObjectDeleter<VideoTrackSupplier> videoSupplierDeleter(
254 		fVideoTrackSupplier);
255 	ObjectDeleter<AudioTrackSupplier> audioSupplierDeleter(
256 		fAudioTrackSupplier);
257 
258 	fVideoTrackSupplier = NULL;
259 	fAudioTrackSupplier = NULL;
260 
261 	fDuration = 0;
262 	fVideoFrameRate = 25.0;
263 
264 	if (fItem.Get() == NULL)
265 		return B_BAD_VALUE;
266 
267 	BMediaFile* mf = fItem->CreateMediaFile();
268 	ObjectDeleter<BMediaFile> mediaFileDeleter(mf);
269 
270 	status_t err = mf->InitCheck();
271 	if (err != B_OK) {
272 		printf("Controller::SetTo: initcheck failed\n");
273 		_NotifyFileChanged(item.Get(), err);
274 		return err;
275 	}
276 
277 	int trackcount = mf->CountTracks();
278 	if (trackcount <= 0) {
279 		printf("Controller::SetTo: trackcount %d\n", trackcount);
280 		_NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
281 		return B_MEDIA_NO_HANDLER;
282 	}
283 
284 	for (int i = 0; i < trackcount; i++) {
285 		BMediaTrack* t = mf->TrackAt(i);
286 		media_format f;
287 		err = t->EncodedFormat(&f);
288 		if (err != B_OK) {
289 			printf("Controller::SetTo: EncodedFormat failed for track index %d, error 0x%08lx (%s)\n",
290 				i, err, strerror(err));
291 			mf->ReleaseTrack(t);
292 			continue;
293 		}
294 
295 		if (t->Duration() <= 0) {
296 			printf("Controller::SetTo: warning! track index %d has no duration\n", i);
297 		}
298 
299 		if (f.IsAudio()) {
300 			if (!fAudioTrackList.AddItem(t))
301 				return B_NO_MEMORY;
302 		} else if (f.IsVideo()) {
303 			if (!fVideoTrackList.AddItem(t))
304 				return B_NO_MEMORY;
305 		} else {
306 			printf("Controller::SetTo: track index %d has unknown type\n", i);
307 			mf->ReleaseTrack(t);
308 		}
309 	}
310 
311 	//printf("Controller::SetTo: %d audio track, %d video track\n",
312 	//	AudioTrackCount(), VideoTrackCount());
313 
314 	fMediaFile = mf;
315 	mediaFileDeleter.Detach();
316 
317 	SelectAudioTrack(0);
318 	SelectVideoTrack(0);
319 
320 	if (fAudioTrackSupplier == NULL && fVideoTrackSupplier == NULL) {
321 		printf("Controller::SetTo: no audio or video tracks found or "
322 			"no decoders\n");
323 		_NotifyFileChanged(item.Get(), B_MEDIA_NO_HANDLER);
324 		delete fMediaFile;
325 		fMediaFile = NULL;
326 		return B_MEDIA_NO_HANDLER;
327 	}
328 
329 	// prevent blocking the creation of new overlay buffers
330 	fVideoView->DisableOverlay();
331 
332 	// get video properties (if there is video at all)
333 	bool useOverlays = fVideoView ? fVideoView->UseOverlays() : true;
334 
335 	int width;
336 	int height;
337 	GetSize(&width, &height);
338 	color_space preferredVideoFormat = B_NO_COLOR_SPACE;
339 	if (fVideoTrackSupplier != NULL) {
340 		const media_format& format = fVideoTrackSupplier->Format();
341 		preferredVideoFormat = format.u.raw_video.display.format;
342 	}
343 
344 	uint32 enabledNodes;
345 	if (!fVideoTrackSupplier)
346 		enabledNodes = AUDIO_ONLY;
347 	else if (!fAudioTrackSupplier)
348 		enabledNodes = VIDEO_ONLY;
349 	else
350 		enabledNodes = AUDIO_AND_VIDEO;
351 
352 	float audioFrameRate = 44100.0f;
353 	uint32 audioChannels = 2;
354 	if (fAudioTrackSupplier != NULL) {
355 		const media_format& audioTrackFormat = fAudioTrackSupplier->Format();
356 		audioFrameRate = audioTrackFormat.u.raw_audio.frame_rate;
357 		audioChannels = audioTrackFormat.u.raw_audio.channel_count;
358 //		if (fVideoTrackSupplier == NULL)
359 //			fVideoFrameRate = audioFrameRate;
360 	}
361 
362 	if (InitCheck() != B_OK) {
363 		Init(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
364 			preferredVideoFormat, audioFrameRate, audioChannels, LOOPING_ALL,
365 			false, 1.0, enabledNodes, useOverlays);
366 	} else {
367 		FormatChanged(BRect(0, 0, width - 1, height - 1), fVideoFrameRate,
368 			preferredVideoFormat, audioFrameRate, audioChannels, enabledNodes,
369 			useOverlays);
370 	}
371 
372 	_NotifyFileChanged(item.Get(), B_OK);
373 
374 	SetPosition(0.0);
375 	if (fAutoplay)
376 		StartPlaying(true);
377 
378 	return B_OK;
379 }
380 
381 
382 void
383 Controller::PlayerActivated(bool active)
384 {
385 	if (LockWithTimeout(5000) != B_OK)
386 		return;
387 
388 	if (active && gMainApp->PlayerCount() > 1) {
389 		if (fActiveVolume != fVolume)
390 			SetVolume(fActiveVolume);
391 	} else {
392 		fActiveVolume = fVolume;
393 		if (gMainApp->PlayerCount() > 1)
394 			switch (fBackgroundMovieVolumeMode) {
395 				case mpSettings::BG_MOVIES_MUTED:
396 					SetVolume(0.0);
397 					break;
398 				case mpSettings::BG_MOVIES_HALF_VLUME:
399 					SetVolume(fVolume * 0.25);
400 					break;
401 				case mpSettings::BG_MOVIES_FULL_VOLUME:
402 				default:
403 					break;
404 			}
405 	}
406 
407 	Unlock();
408 }
409 
410 
411 void
412 Controller::GetSize(int *width, int *height, int* _widthAspect,
413 	int* _heightAspect)
414 {
415 	BAutolock _(this);
416 
417 	if (fVideoTrackSupplier) {
418 		media_format format = fVideoTrackSupplier->Format();
419 		*height = format.u.raw_video.display.line_count;
420 		*width = format.u.raw_video.display.line_width;
421 		int widthAspect = 0;
422 		int heightAspect = 0;
423 		// Ignore format aspect when both values are 1. If they have been
424 		// intentionally at 1:1 then no harm is done for quadratic videos,
425 		// only if the video is indeed encoded anamorphotic, but supposed
426 		// to be displayed quadratic... extremely unlikely.
427 		if (format.u.raw_video.pixel_width_aspect
428 			!= format.u.raw_video.pixel_height_aspect
429 			&& format.u.raw_video.pixel_width_aspect != 1) {
430 			widthAspect = format.u.raw_video.pixel_width_aspect;
431 			heightAspect = format.u.raw_video.pixel_height_aspect;
432 		}
433 		if (_widthAspect != NULL)
434 			*_widthAspect = widthAspect;
435 		if (_heightAspect != NULL)
436 			*_heightAspect = heightAspect;
437 	} else {
438 		*height = 0;
439 		*width = 0;
440 		if (_widthAspect != NULL)
441 			*_widthAspect = 1;
442 		if (_heightAspect != NULL)
443 			*_heightAspect = 1;
444 	}
445 }
446 
447 
448 int
449 Controller::AudioTrackCount()
450 {
451 	BAutolock _(this);
452 
453 	return fAudioTrackList.CountItems();
454 }
455 
456 
457 int
458 Controller::VideoTrackCount()
459 {
460 	BAutolock _(this);
461 
462 	return fVideoTrackList.CountItems();
463 }
464 
465 
466 status_t
467 Controller::SelectAudioTrack(int n)
468 {
469 	BAutolock _(this);
470 
471 	BMediaTrack* track = (BMediaTrack *)fAudioTrackList.ItemAt(n);
472 	if (!track)
473 		return B_ERROR;
474 
475 	ObjectDeleter<AudioTrackSupplier> deleter(fAudioTrackSupplier);
476 	fAudioTrackSupplier = new MediaTrackAudioSupplier(track, n);
477 
478 	bigtime_t a = fAudioTrackSupplier->Duration();
479 	bigtime_t v = fVideoTrackSupplier ? fVideoTrackSupplier->Duration() : 0;;
480 	fDuration = max_c(a, v);
481 	DurationChanged();
482 	// TODO: notify duration changed!
483 
484 	fAudioSupplier->SetSupplier(fAudioTrackSupplier, fVideoFrameRate);
485 
486 	_NotifyAudioTrackChanged(n);
487 	return B_OK;
488 }
489 
490 
491 int
492 Controller::CurrentAudioTrack()
493 {
494 	BAutolock _(this);
495 
496 	if (fAudioTrackSupplier == NULL)
497 		return -1;
498 
499 	return fAudioTrackSupplier->TrackIndex();
500 }
501 
502 
503 status_t
504 Controller::SelectVideoTrack(int n)
505 {
506 	BAutolock _(this);
507 
508 	BMediaTrack* track = (BMediaTrack *)fVideoTrackList.ItemAt(n);
509 	if (!track)
510 		return B_ERROR;
511 
512 	status_t initStatus;
513 	ObjectDeleter<VideoTrackSupplier> deleter(fVideoTrackSupplier);
514 	fVideoTrackSupplier = new MediaTrackVideoSupplier(track, n, initStatus);
515 	if (initStatus < B_OK) {
516 		delete fVideoTrackSupplier;
517 		fVideoTrackSupplier = NULL;
518 		return initStatus;
519 	}
520 
521 	bigtime_t a = fAudioTrackSupplier ? fAudioTrackSupplier->Duration() : 0;
522 	bigtime_t v = fVideoTrackSupplier->Duration();
523 	fDuration = max_c(a, v);
524 	fVideoFrameRate = fVideoTrackSupplier->Format().u.raw_video.field_rate;
525 	if (fVideoFrameRate <= 0.0) {
526 		printf("Controller::SelectVideoTrack(%d) - invalid video frame rate: %.1f\n",
527 			n, fVideoFrameRate);
528 		fVideoFrameRate = 25.0;
529 	}
530 
531 	DurationChanged();
532 	// TODO: notify duration changed!
533 
534 	fVideoSupplier->SetSupplier(fVideoTrackSupplier);
535 
536 	_NotifyVideoTrackChanged(n);
537 	return B_OK;
538 }
539 
540 
541 int
542 Controller::CurrentVideoTrack()
543 {
544 	BAutolock _(this);
545 
546 	if (fVideoTrackSupplier == NULL)
547 		return -1;
548 
549 	return fVideoTrackSupplier->TrackIndex();
550 }
551 
552 
553 // #pragma mark -
554 
555 
556 void
557 Controller::Stop()
558 {
559 	//printf("Controller::Stop\n");
560 
561 	BAutolock _(this);
562 
563 	StopPlaying();
564 	SetPosition(0.0);
565 
566 	fAutoplay = fAutoplaySetting;
567 }
568 
569 
570 void
571 Controller::Play()
572 {
573 	//printf("Controller::Play\n");
574 
575 	BAutolock _(this);
576 
577 	StartPlaying();
578 	fAutoplay = true;
579 }
580 
581 
582 void
583 Controller::Pause()
584 {
585 //	printf("Controller::Pause\n");
586 
587 	BAutolock _(this);
588 
589 	PausePlaying();
590 
591 	fAutoplay = fAutoplaySetting;
592 }
593 
594 
595 void
596 Controller::TogglePlaying()
597 {
598 //	printf("Controller::TogglePlaying\n");
599 
600 	BAutolock _(this);
601 
602 	if (InitCheck() == B_OK) {
603 		NodeManager::TogglePlaying();
604 
605 		fAutoplay = IsPlaying() || fAutoplaySetting;
606 	}
607 }
608 
609 
610 uint32
611 Controller::PlaybackState()
612 {
613 	BAutolock _(this);
614 
615 	return _PlaybackState(PlaybackManager::PlayMode());
616 }
617 
618 
619 bigtime_t
620 Controller::TimeDuration()
621 {
622 	BAutolock _(this);
623 
624 	return fDuration;
625 }
626 
627 
628 bigtime_t
629 Controller::TimePosition()
630 {
631 	BAutolock _(this);
632 
633 	return fPosition;
634 }
635 
636 
637 void
638 Controller::SetVolume(float value)
639 {
640 //	printf("Controller::SetVolume %.4f\n", value);
641 	if (!Lock())
642 		return;
643 
644 	value = max_c(0.0, min_c(2.0, value));
645 
646 	if (fVolume != value) {
647 		if (fMuted)
648 			ToggleMute();
649 
650 		fVolume = value;
651 		fAudioSupplier->SetVolume(fVolume);
652 
653 		_NotifyVolumeChanged(fVolume);
654 	}
655 
656 	Unlock();
657 }
658 
659 void
660 Controller::VolumeUp()
661 {
662 	// TODO: linear <-> exponential
663 	SetVolume(Volume() + 0.05);
664 }
665 
666 void
667 Controller::VolumeDown()
668 {
669 	// TODO: linear <-> exponential
670 	SetVolume(Volume() - 0.05);
671 }
672 
673 void
674 Controller::ToggleMute()
675 {
676 	if (!Lock())
677 		return;
678 
679 	fMuted = !fMuted;
680 
681 	if (fMuted)
682 		fAudioSupplier->SetVolume(0.0);
683 	else
684 		fAudioSupplier->SetVolume(fVolume);
685 
686 	_NotifyMutedChanged(fMuted);
687 
688 	Unlock();
689 }
690 
691 
692 float
693 Controller::Volume()
694 {
695 	BAutolock _(this);
696 
697 	return fVolume;
698 }
699 
700 
701 void
702 Controller::SetPosition(float value)
703 {
704 	BAutolock _(this);
705 
706 	SetFramePosition(Duration() * value);
707 }
708 
709 
710 void
711 Controller::SetFramePosition(int32 value)
712 {
713 	BAutolock _(this);
714 
715 	int32 seekFrame = max_c(0, min_c(Duration(), value));
716 	int32 currentFrame = CurrentFrame();
717 	if (seekFrame != currentFrame) {
718 		fSeekFrame = seekFrame;
719 		fSeekRequested = true;
720 		SetCurrentFrame(seekFrame);
721 	}
722 }
723 
724 
725 void
726 Controller::SetTimePosition(bigtime_t value)
727 {
728 	BAutolock _(this);
729 
730 	SetPosition((float)value / TimeDuration());
731 }
732 
733 
734 // #pragma mark -
735 
736 
737 bool
738 Controller::HasFile()
739 {
740 	// you need to hold the data lock
741 	return fMediaFile != NULL;
742 }
743 
744 
745 status_t
746 Controller::GetFileFormatInfo(media_file_format* fileFormat)
747 {
748 	// you need to hold the data lock
749 	if (!fMediaFile)
750 		return B_NO_INIT;
751 	return fMediaFile->GetFileFormatInfo(fileFormat);
752 }
753 
754 
755 status_t
756 Controller::GetCopyright(BString* copyright)
757 {
758 	// you need to hold the data lock
759 	if (!fMediaFile)
760 		return B_NO_INIT;
761 	*copyright = fMediaFile->Copyright();
762 	return B_OK;
763 }
764 
765 
766 status_t
767 Controller::GetLocation(BString* location)
768 {
769 	// you need to hold the data lock
770 	if (fItem.Get() == NULL)
771 		return B_NO_INIT;
772 	*location = fItem->LocationURI();
773 	return B_OK;
774 }
775 
776 
777 status_t
778 Controller::GetName(BString* name)
779 {
780 	// you need to hold the data lock
781 	if (fItem.Get() == NULL)
782 		return B_NO_INIT;
783 	*name = fItem->Name();
784 	return B_OK;
785 }
786 
787 
788 status_t
789 Controller::GetEncodedVideoFormat(media_format* format)
790 {
791 	// you need to hold the data lock
792 	if (fVideoTrackSupplier)
793 		return fVideoTrackSupplier->GetEncodedFormat(format);
794 	return B_NO_INIT;
795 }
796 
797 
798 status_t
799 Controller::GetVideoCodecInfo(media_codec_info* info)
800 {
801 	// you need to hold the data lock
802 	if (fVideoTrackSupplier)
803 		return fVideoTrackSupplier->GetCodecInfo(info);
804 	return B_NO_INIT;
805 }
806 
807 
808 status_t
809 Controller::GetEncodedAudioFormat(media_format* format)
810 {
811 	// you need to hold the data lock
812 	if (fAudioTrackSupplier)
813 		return fAudioTrackSupplier->GetEncodedFormat(format);
814 	return B_NO_INIT;
815 }
816 
817 
818 status_t
819 Controller::GetAudioCodecInfo(media_codec_info* info)
820 {
821 	// you need to hold the data lock
822 	if (fAudioTrackSupplier)
823 		return fAudioTrackSupplier->GetCodecInfo(info);
824 	return B_NO_INIT;
825 }
826 
827 
828 // #pragma mark -
829 
830 
831 void
832 Controller::SetVideoView(VideoView *view)
833 {
834 	BAutolock _(this);
835 
836 	fVideoView = view;
837 }
838 
839 
840 bool
841 Controller::IsOverlayActive()
842 {
843 	if (fVideoView)
844 		return fVideoView->IsOverlayActive();
845 
846 	return false;
847 }
848 
849 
850 // #pragma mark -
851 
852 
853 bool
854 Controller::AddListener(Listener* listener)
855 {
856 	BAutolock _(this);
857 
858 	if (listener && !fListeners.HasItem(listener))
859 		return fListeners.AddItem(listener);
860 	return false;
861 }
862 
863 
864 void
865 Controller::RemoveListener(Listener* listener)
866 {
867 	BAutolock _(this);
868 
869 	fListeners.RemoveItem(listener);
870 }
871 
872 
873 // #pragma mark - Private
874 
875 
876 void
877 Controller::_AdoptGlobalSettings()
878 {
879 	mpSettings settings = Settings::CurrentSettings();
880 		// thread safe
881 
882 	fAutoplaySetting = settings.autostart;
883 	// not yet used:
884 	fLoopMovies = settings.loopMovie;
885 	fLoopSounds = settings.loopSound;
886 	fBackgroundMovieVolumeMode = settings.backgroundMovieVolumeMode;
887 }
888 
889 
890 uint32
891 Controller::_PlaybackState(int32 playingMode) const
892 {
893 	uint32 state = 0;
894 	switch (playingMode) {
895 		case MODE_PLAYING_PAUSED_FORWARD:
896 		case MODE_PLAYING_PAUSED_BACKWARD:
897 			state = PLAYBACK_STATE_PAUSED;
898 			break;
899 		case MODE_PLAYING_FORWARD:
900 		case MODE_PLAYING_BACKWARD:
901 			state = PLAYBACK_STATE_PLAYING;
902 			break;
903 
904 		default:
905 			state = PLAYBACK_STATE_STOPPED;
906 			break;
907 	}
908 	return state;
909 }
910 
911 
912 // #pragma mark - Notifications
913 
914 
915 void
916 Controller::_NotifyFileChanged(PlaylistItem* item, status_t result) const
917 {
918 	BList listeners(fListeners);
919 	int32 count = listeners.CountItems();
920 	for (int32 i = 0; i < count; i++) {
921 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
922 		listener->FileChanged(item, result);
923 	}
924 }
925 
926 
927 void
928 Controller::_NotifyFileFinished() const
929 {
930 	BList listeners(fListeners);
931 	int32 count = listeners.CountItems();
932 	for (int32 i = 0; i < count; i++) {
933 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
934 		listener->FileFinished();
935 	}
936 }
937 
938 
939 void
940 Controller::_NotifyVideoTrackChanged(int32 index) const
941 {
942 	BList listeners(fListeners);
943 	int32 count = listeners.CountItems();
944 	for (int32 i = 0; i < count; i++) {
945 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
946 		listener->VideoTrackChanged(index);
947 	}
948 }
949 
950 
951 void
952 Controller::_NotifyAudioTrackChanged(int32 index) const
953 {
954 	BList listeners(fListeners);
955 	int32 count = listeners.CountItems();
956 	for (int32 i = 0; i < count; i++) {
957 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
958 		listener->AudioTrackChanged(index);
959 	}
960 }
961 
962 
963 void
964 Controller::_NotifyVideoStatsChanged() const
965 {
966 	BList listeners(fListeners);
967 	int32 count = listeners.CountItems();
968 	for (int32 i = 0; i < count; i++) {
969 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
970 		listener->VideoStatsChanged();
971 	}
972 }
973 
974 
975 void
976 Controller::_NotifyAudioStatsChanged() const
977 {
978 	BList listeners(fListeners);
979 	int32 count = listeners.CountItems();
980 	for (int32 i = 0; i < count; i++) {
981 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
982 		listener->AudioStatsChanged();
983 	}
984 }
985 
986 
987 void
988 Controller::_NotifyPlaybackStateChanged(uint32 state) const
989 {
990 	BList listeners(fListeners);
991 	int32 count = listeners.CountItems();
992 	for (int32 i = 0; i < count; i++) {
993 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
994 		listener->PlaybackStateChanged(state);
995 	}
996 }
997 
998 
999 void
1000 Controller::_NotifyPositionChanged(float position) const
1001 {
1002 	BList listeners(fListeners);
1003 	int32 count = listeners.CountItems();
1004 	for (int32 i = 0; i < count; i++) {
1005 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1006 		listener->PositionChanged(position);
1007 	}
1008 }
1009 
1010 
1011 void
1012 Controller::_NotifyVolumeChanged(float volume) const
1013 {
1014 	BList listeners(fListeners);
1015 	int32 count = listeners.CountItems();
1016 	for (int32 i = 0; i < count; i++) {
1017 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1018 		listener->VolumeChanged(volume);
1019 	}
1020 }
1021 
1022 
1023 void
1024 Controller::_NotifyMutedChanged(bool muted) const
1025 {
1026 	BList listeners(fListeners);
1027 	int32 count = listeners.CountItems();
1028 	for (int32 i = 0; i < count; i++) {
1029 		Listener* listener = (Listener*)listeners.ItemAtFast(i);
1030 		listener->MutedChanged(muted);
1031 	}
1032 }
1033 
1034 
1035 void
1036 Controller::NotifyPlayModeChanged(int32 mode) const
1037 {
1038 	uint32 state = _PlaybackState(mode);
1039 	if (fVideoView)
1040 		fVideoView->SetPlaying(state == PLAYBACK_STATE_PLAYING);
1041 	_NotifyPlaybackStateChanged(state);
1042 }
1043 
1044 
1045 void
1046 Controller::NotifyLoopModeChanged(int32 mode) const
1047 {
1048 }
1049 
1050 
1051 void
1052 Controller::NotifyLoopingEnabledChanged(bool enabled) const
1053 {
1054 }
1055 
1056 
1057 void
1058 Controller::NotifyVideoBoundsChanged(BRect bounds) const
1059 {
1060 }
1061 
1062 
1063 void
1064 Controller::NotifyFPSChanged(float fps) const
1065 {
1066 }
1067 
1068 
1069 void
1070 Controller::NotifyCurrentFrameChanged(int32 frame) const
1071 {
1072 	// check if we are still waiting to reach the seekframe,
1073 	// don't pass the event on to the listeners in that case
1074 	if (fSeekRequested && fSeekFrame != frame)
1075 		return;
1076 
1077 	fSeekFrame = -1;
1078 	fSeekRequested = false;
1079 
1080 	float position = 0.0;
1081 	double duration = (double)fDuration * fVideoFrameRate / 1000000.0;
1082 	if (duration > 0)
1083 		position = (float)frame / duration;
1084 	fPosition = (bigtime_t)(position * fDuration + 0.5);
1085 	_NotifyPositionChanged(position);
1086 }
1087 
1088 
1089 void
1090 Controller::NotifySpeedChanged(float speed) const
1091 {
1092 }
1093 
1094 
1095 void
1096 Controller::NotifyFrameDropped() const
1097 {
1098 //	printf("Controller::NotifyFrameDropped()\n");
1099 }
1100 
1101 
1102 void
1103 Controller::NotifyStopFrameReached() const
1104 {
1105 	// Currently, this means we reached the end of the current
1106 	// file and should play the next file
1107 	_NotifyFileFinished();
1108 }
1109 
1110 
1111 void
1112 Controller::NotifySeekHandled() const
1113 {
1114 	fSeekRequested = false;
1115 	fSeekFrame = -1;
1116 }
1117 
1118