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