sbMediacoreSequencer.cpp
Go to the documentation of this file.
1 /* vim: set sw=2 :miv */
2 /*
3  *=BEGIN SONGBIRD GPL
4  *
5  * This file is part of the Songbird web player.
6  *
7  * Copyright(c) 2005-2010 POTI, Inc.
8  * http://www.songbirdnest.com
9  *
10  * This file may be licensed under the terms of of the
11  * GNU General Public License Version 2 (the ``GPL'').
12  *
13  * Software distributed under the License is distributed
14  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
15  * express or implied. See the GPL for the specific language
16  * governing rights and limitations.
17  *
18  * You should have received a copy of the GPL along with this
19  * program. If not, go to http://www.gnu.org/licenses/gpl.html
20  * or write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  *
23  *=END SONGBIRD GPL
24  */
25 
26 #include "sbMediacoreSequencer.h"
27 
28 #include <nsIClassInfoImpl.h>
29 #include <nsIDOMWindow.h>
30 #include <nsIDOMXULElement.h>
31 #include <nsIPrefBranch.h>
32 #include <nsIPrefService.h>
33 #include <nsIProgrammingLanguage.h>
34 #include <nsIPropertyBag2.h>
35 #include <nsISupportsPrimitives.h>
36 #include <nsIURL.h>
37 #include <nsIVariant.h>
38 #include <nsIWeakReferenceUtils.h>
39 #include <nsIWindowWatcher.h>
40 
41 #include <nsAutoLock.h>
42 #include <nsAutoPtr.h>
43 #include <nsArrayUtils.h>
44 #include <nsComponentManagerUtils.h>
45 
46 #include <nsMemory.h>
47 #include <nsServiceManagerUtils.h>
48 #include <nsStringGlue.h>
49 #include <nsTArray.h>
50 
51 #include <prtime.h>
52 
53 #include <sbICascadeFilterSet.h>
54 #include <sbIFilterableMediaListView.h>
55 #include <sbILibrary.h>
56 #include <sbILibraryConstraints.h>
57 #include <sbIMediacore.h>
58 #include <sbIMediacoreEvent.h>
59 #include <sbIMediacoreEventTarget.h>
60 #include <sbIMediacorePlaybackControl.h>
61 #include <sbIMediacoreStatus.h>
62 #include <sbIMediacoreVideoWindow.h>
63 #include <sbIMediacoreVoting.h>
64 #include <sbIMediacoreVotingChain.h>
65 #include <sbIMediaItem.h>
66 #include <sbIMediaItemController.h>
67 #include <sbIMediaList.h>
68 #include <sbIPrompter.h>
69 #include <sbIPropertyArray.h>
70 #include <sbIPropertyInfo.h>
71 #include <sbISortableMediaListView.h>
72 #include <sbIWindowWatcher.h>
73 #include <sbIMediacoreErrorHandler.h>
74 
76 #include <sbMediacoreError.h>
77 #include <sbMediacoreEvent.h>
78 #include <sbMemoryUtils.h>
80 #include <sbStandardProperties.h>
81 #include <sbStringBundle.h>
82 #include <sbStringUtils.h>
84 #include <sbThreadUtils.h>
85 #include <sbVariantUtils.h>
86 
87 #include "sbMediacoreDataRemotes.h"
89 
90 // Time in ms between dataremote updates
91 #define MEDIACORE_UPDATE_NOTIFICATION_DELAY 500
92 
93 // Time in ms to wait before deferred media list check
94 #define MEDIACORE_CHECK_DELAY 100
95 
96 // Number of errors after which to stop flipping to next track
97 #define MEDIACORE_MAX_SUBSEQUENT_ERRORS 20
98 
103 #ifdef PR_LOGGING
104 static PRLogModuleInfo* gMediacoreSequencerLog = nsnull;
105 #define TRACE(args) PR_LOG(gMediacoreSequencerLog, PR_LOG_DEBUG, args)
106 #define LOG(args) PR_LOG(gMediacoreSequencerLog, PR_LOG_WARN, args)
107 #else
108 #define TRACE(args) /* nothing */
109 #define LOG(args) /* nothing */
110 #endif
111 
112 inline nsresult
114  nsAString &aString,
115  PRBool aRemainingTime = PR_FALSE)
116 {
117  PRUint64 seconds = aValue / 1000;
118  PRUint64 minutes = seconds / 60;
119  PRUint64 hours = minutes / 60;
120 
121  seconds = seconds %60;
122  minutes = minutes % 60;
123 
124  NS_NAMED_LITERAL_STRING(strZero, "0");
125  NS_NAMED_LITERAL_STRING(strCol, ":");
126  nsString stringValue;
127 
128  if(hours > 0) {
129  AppendInt(stringValue, hours);
130  stringValue += strCol;
131  }
132 
133  if(hours > 0 && minutes < 10) {
134  stringValue += strZero;
135  }
136 
137  AppendInt(stringValue, minutes);
138  stringValue += strCol;
139 
140  if(seconds < 10) {
141  stringValue += strZero;
142  }
143 
144  AppendInt(stringValue, seconds);
145 
146  aString.Truncate();
147 
148  if(aRemainingTime) {
149  aString.Assign(NS_LITERAL_STRING("-"));
150  }
151 
152  aString.Append(stringValue);
153 
154  return NS_OK;
155 }
156 
157 //------------------------------------------------------------------------------
158 // sbMediacoreSequencer
159 //------------------------------------------------------------------------------
160 
163 
170  nsIClassInfo,
172 
173 NS_IMPL_CI_INTERFACE_GETTER2(sbMediacoreSequencer,
174  sbIMediacoreSequencer,
175  sbIMediacoreStatus)
176 
177 NS_DECL_CLASSINFO(sbMediacoreSequencer)
178 NS_IMPL_THREADSAFE_CI(sbMediacoreSequencer)
179 
180 sbMediacoreSequencer::sbMediacoreSequencer()
181 : mMonitor(nsnull)
182 , mStatus(sbIMediacoreStatus::STATUS_STOPPED)
183 , mIsWaitingForPlayback(PR_FALSE)
184 , mSeenPlaying(PR_FALSE)
185 , mNextTriggeredByStreamEnd(PR_FALSE)
186 , mStopTriggeredBySequencer(PR_FALSE)
187 , mCoreWillHandleNext(PR_FALSE)
188 , mPositionInvalidated(PR_FALSE)
189 , mErrorCount(0)
190 , mCanAbort(PR_FALSE)
191 , mShouldAbort(PR_FALSE)
192 , mMode(sbIMediacoreSequencer::MODE_FORWARD)
193 , mRepeatMode(sbIMediacoreSequencer::MODE_REPEAT_NONE)
194 , mPosition(0)
195 , mViewPosition(0)
196 , mCurrentItemIndex(0)
197 , mListBatchCount(0)
198 , mLibraryBatchCount(0)
199 , mSmartRebuildDetectBatchCount(0)
200 , mResetPosition(PR_FALSE)
201 , mNoRecalculate(PR_FALSE)
202 , mViewIsLibrary(PR_FALSE)
203 , mNeedSearchPlayingItem(PR_FALSE)
204 , mNeedsRecalculate(PR_FALSE)
205 , mWatchingView(PR_FALSE)
206 , mResumePlaybackPosition(PR_TRUE)
207 , mValidationComplete(PR_FALSE)
208 , mOnHoldStatus(ONHOLD_NOTONHOLD)
209 , mValidationFromUserAction(PR_FALSE)
210 {
211 
212 #ifdef PR_LOGGING
213  if (!gMediacoreSequencerLog)
214  gMediacoreSequencerLog = PR_NewLogModule("sbMediacoreSequencer");
215 #endif
216 }
217 
219 {
220  if(mMonitor) {
221  nsAutoMonitor::DestroyMonitor(mMonitor);
222  }
223 
225 }
226 
227 nsresult
229 {
230  NS_ASSERTION(NS_IsMainThread(),
231  "sbMediacoreSequencer::Init expected to be on the main thread");
232  mMonitor = nsAutoMonitor::NewMonitor("sbMediacoreSequencer::mMonitor");
233  NS_ENSURE_TRUE(mMonitor, NS_ERROR_OUT_OF_MEMORY);
234 
235  nsresult rv = NS_ERROR_UNEXPECTED;
236 
237  nsCOMPtr<nsISupportsWeakReference> weakRef =
238  do_GetService(SB_MEDIACOREMANAGER_CONTRACTID, &rv);
239  NS_ENSURE_SUCCESS(rv, rv);
240 
241  rv = weakRef->GetWeakReference(getter_AddRefs(mMediacoreManager));
242  NS_ENSURE_SUCCESS(rv, rv);
243 
245  do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
246  NS_ENSURE_SUCCESS(rv, rv);
247 
248  rv = BindDataRemotes();
249  NS_ENSURE_SUCCESS(rv, rv);
250 
251  nsRefPtr<sbMediacoreShuffleSequenceGenerator> generator;
252  NS_NEWXPCOM(generator, sbMediacoreShuffleSequenceGenerator);
253  NS_ENSURE_TRUE(generator, NS_ERROR_OUT_OF_MEMORY);
254 
255  rv = generator->Init();
256  NS_ENSURE_SUCCESS(rv, rv);
257 
258  mShuffleGenerator = do_QueryInterface(generator, &rv);
259  NS_ENSURE_SUCCESS(rv, rv);
260 
261  PRBool shuffle = PR_FALSE;
262  rv = mDataRemotePlaylistShuffle->GetBoolValue(&shuffle);
263  NS_ENSURE_SUCCESS(rv, rv);
264 
265  if(shuffle) {
267  }
268 
269  PRInt64 repeatMode = 0;
270  rv = mDataRemotePlaylistRepeat->GetIntValue(&repeatMode);
271  NS_ENSURE_SUCCESS(rv, rv);
272  NS_ENSURE_ARG_RANGE(repeatMode, 0, 2);
273 
274  mRepeatMode = (PRUint32)repeatMode;
275 
276  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
277  NS_ENSURE_SUCCESS(rv, rv);
278  PRBool doResume;
279  rv = prefs->GetBoolPref("songbird.mediacore.resumePlaybackPosition",
280  &doResume);
281  if (NS_SUCCEEDED(rv)) {
282  // only set the member we actually check if the pref was retrieved
283  mResumePlaybackPosition = doResume ? PR_TRUE : PR_FALSE;
284  }
285 
286  return NS_OK;
287 }
288 
289 nsresult
291 {
292  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
293  NS_ENSURE_TRUE(mSequenceProcessorTimer, NS_ERROR_NOT_INITIALIZED);
294 
295  nsresult rv =
296  mSequenceProcessorTimer->InitWithCallback(this,
298  nsITimer::TYPE_REPEATING_SLACK);
299  NS_ENSURE_SUCCESS(rv, rv);
300 
301  rv = StartWatchingView();
302  NS_ENSURE_SUCCESS(rv, rv);
303 
304  return NS_OK;
305 }
306 
307 nsresult
309 {
310  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
311  NS_ENSURE_TRUE(mSequenceProcessorTimer, NS_ERROR_NOT_INITIALIZED);
312 
313  nsresult rv = mSequenceProcessorTimer->Cancel();
314  NS_ENSURE_SUCCESS(rv, rv);
315 
317  NS_ENSURE_SUCCESS(rv, rv);
318 
320  NS_ENSURE_SUCCESS(rv, rv);
321 
322  rv = StopWatchingView();
323  NS_ENSURE_SUCCESS(rv, rv);
324 
325  return NS_OK;
326 }
327 
328 nsresult
330 {
331  nsresult rv = NS_ERROR_UNEXPECTED;
332 
333  //
334  // Faceplate DataRemotes
335  //
336 
337  nsString nullString;
338  nullString.SetIsVoid(PR_TRUE);
339 
340  // Faceplate Buffering
342  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
343  NS_ENSURE_SUCCESS(rv, rv);
344 
347  nullString);
348  NS_ENSURE_SUCCESS(rv, rv);
349 
350  rv = mDataRemoteFaceplateBuffering->SetBoolValue(PR_FALSE);
351  NS_ENSURE_SUCCESS(rv, rv);
352 
353  // Faceplate Paused
355  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
356  NS_ENSURE_SUCCESS(rv, rv);
357 
358  rv = mDataRemoteFaceplatePaused->Init(
359  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_FACEPLATE_PAUSED),
360  nullString);
361  NS_ENSURE_SUCCESS(rv, rv);
362 
363  rv = mDataRemoteFaceplatePaused->SetBoolValue(PR_FALSE);
364  NS_ENSURE_SUCCESS(rv, rv);
365 
366  // Faceplate Playing
368  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
369  NS_ENSURE_SUCCESS(rv, rv);
370 
371  rv = mDataRemoteFaceplatePlaying->Init(
373  nullString);
374  NS_ENSURE_SUCCESS(rv, rv);
375 
376  rv = mDataRemoteFaceplatePlaying->SetBoolValue(PR_FALSE);
377  NS_ENSURE_SUCCESS(rv, rv);
378 
379  // Faceplate Playing Video
381  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
382  NS_ENSURE_SUCCESS(rv, rv);
383 
386  nullString);
387  NS_ENSURE_SUCCESS(rv, rv);
388 
389  rv = mDataRemoteFaceplatePlayingVideo->SetBoolValue(PR_FALSE);
390  NS_ENSURE_SUCCESS(rv, rv);
391 
392  // Faceplate Seen Playing
394  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
395  NS_ENSURE_SUCCESS(rv, rv);
396 
399  nullString);
400  NS_ENSURE_SUCCESS(rv, rv);
401 
402  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_FALSE);
403  NS_ENSURE_SUCCESS(rv, rv);
404 
405  //Faceplate Play URL
407  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
408  NS_ENSURE_SUCCESS(rv, rv);
409 
410  rv = mDataRemoteFaceplateURL->Init(
412  nullString);
413  NS_ENSURE_SUCCESS(rv, rv);
414 
415  rv = mDataRemoteFaceplateURL->SetStringValue(EmptyString());
416  NS_ENSURE_SUCCESS(rv, rv);
417 
418  // Faceplate Volume
420  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
421  NS_ENSURE_SUCCESS(rv, rv);
422 
423  rv = mDataRemoteFaceplateVolume->Init(
424  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_FACEPLATE_VOLUME),
425  nullString);
426 
427  // Faceplate Mute
429  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
430  NS_ENSURE_SUCCESS(rv, rv);
431 
432  rv = mDataRemoteFaceplateMute->Init(
433  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_FACEPLATE_MUTE),
434  nullString);
435  NS_ENSURE_SUCCESS(rv, rv);
436 
437  //
438  // Metadata DataRemotes
439  //
440 
441  // Metadata Album
443  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
444  NS_ENSURE_SUCCESS(rv, rv);
445 
446  rv = mDataRemoteMetadataAlbum->Init(
447  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_METADATA_ALBUM),
448  nullString);
449  NS_ENSURE_SUCCESS(rv, rv);
450 
451  rv = mDataRemoteMetadataAlbum->SetStringValue(EmptyString());
452  NS_ENSURE_SUCCESS(rv, rv);
453 
454  // Metadata Artist
456  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
457  NS_ENSURE_SUCCESS(rv, rv);
458 
459  rv = mDataRemoteMetadataArtist->Init(
460  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_METADATA_ARTIST),
461  nullString);
462  NS_ENSURE_SUCCESS(rv, rv);
463 
464  rv = mDataRemoteMetadataArtist->SetStringValue(EmptyString());
465  NS_ENSURE_SUCCESS(rv, rv);
466 
467  // Metadata Genre
469  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
470  NS_ENSURE_SUCCESS(rv, rv);
471 
472  rv = mDataRemoteMetadataGenre->Init(
473  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_METADATA_GENRE),
474  nullString);
475  NS_ENSURE_SUCCESS(rv, rv);
476 
477 
478  rv = mDataRemoteMetadataGenre->SetStringValue(EmptyString());
479  NS_ENSURE_SUCCESS(rv, rv);
480 
481  // Metadata Title
483  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
484  NS_ENSURE_SUCCESS(rv, rv);
485 
486  rv = mDataRemoteMetadataTitle->Init(
487  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_METADATA_TITLE),
488  nullString);
489  NS_ENSURE_SUCCESS(rv, rv);
490 
491  rv = mDataRemoteMetadataTitle->SetStringValue(EmptyString());
492  NS_ENSURE_SUCCESS(rv, rv);
493 
494  // Metadata Duration
496  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
497  NS_ENSURE_SUCCESS(rv, rv);
498 
499  rv = mDataRemoteMetadataDuration->Init(
500  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_METADATA_LENGTH),
501  nullString);
502  NS_ENSURE_SUCCESS(rv, rv);
503 
504  rv = mDataRemoteMetadataDuration->SetIntValue(0);
505  NS_ENSURE_SUCCESS(rv, rv);
506 
507  // Metadata Duration Str
509  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
510  NS_ENSURE_SUCCESS(rv, rv);
511 
514  nullString);
515  NS_ENSURE_SUCCESS(rv, rv);
516 
517  rv = mDataRemoteMetadataDurationStr->SetStringValue(NS_LITERAL_STRING("0:00"));
518  NS_ENSURE_SUCCESS(rv, rv);
519 
520  // Metadata Position
522  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
523  NS_ENSURE_SUCCESS(rv, rv);
524 
525  rv = mDataRemoteMetadataPosition->Init(
527  nullString);
528  NS_ENSURE_SUCCESS(rv, rv);
529 
530  rv = mDataRemoteMetadataPosition->SetIntValue(0);
531  NS_ENSURE_SUCCESS(rv, rv);
532 
533  // Metadata Position Str
535  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
536  NS_ENSURE_SUCCESS(rv, rv);
537 
540  nullString);
541  NS_ENSURE_SUCCESS(rv, rv);
542 
543  rv =
544  mDataRemoteMetadataPositionStr->SetStringValue(NS_LITERAL_STRING("0:00"));
545  NS_ENSURE_SUCCESS(rv, rv);
546 
547  // Metadata Remaining Str
549  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
550  NS_ENSURE_SUCCESS(rv, rv);
551 
554  nullString);
555  NS_ENSURE_SUCCESS(rv, rv);
556 
557  rv =
558  mDataRemoteMetadataRemainingStr->SetStringValue(NS_LITERAL_STRING("0:00"));
559  NS_ENSURE_SUCCESS(rv, rv);
560 
561  // Metadata URL
563  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
564  NS_ENSURE_SUCCESS(rv, rv);
565 
566  rv = mDataRemoteMetadataURL->Init(
567  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_METADATA_URL),
568  nullString);
569  NS_ENSURE_SUCCESS(rv, rv);
570 
571  rv = mDataRemoteMetadataURL->SetStringValue(EmptyString());
572  NS_ENSURE_SUCCESS(rv, rv);
573 
574  // Metadata image URL
576  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
577  NS_ENSURE_SUCCESS(rv, rv);
578 
579  rv = mDataRemoteMetadataImageURL->Init(
581  nullString);
582  NS_ENSURE_SUCCESS(rv, rv);
583 
584  rv = mDataRemoteMetadataImageURL->SetStringValue(EmptyString());
585  NS_ENSURE_SUCCESS(rv, rv);
586 
587  // Playlist Shuffle
589  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
590  NS_ENSURE_SUCCESS(rv, rv);
591 
592  rv = mDataRemotePlaylistShuffle->Init(
593  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_PLAYLIST_SHUFFLE),
594  nullString);
595  NS_ENSURE_SUCCESS(rv, rv);
596 
597  nsString shuffle;
598  rv = mDataRemotePlaylistShuffle->GetStringValue(shuffle);
599  NS_ENSURE_SUCCESS(rv, rv);
600 
601  if(shuffle.IsEmpty()) {
602  rv = mDataRemotePlaylistShuffle->SetBoolValue(PR_FALSE);
603  NS_ENSURE_SUCCESS(rv, rv);
604  }
605 
606  // Playlist Repeat
608  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
609  NS_ENSURE_SUCCESS(rv, rv);
610 
611  rv = mDataRemotePlaylistRepeat->Init(
612  NS_LITERAL_STRING(SB_MEDIACORE_DATAREMOTE_PLAYLIST_REPEAT),
613  nullString);
614  NS_ENSURE_SUCCESS(rv, rv);
615 
616  nsString repeat;
617  rv = mDataRemotePlaylistRepeat->GetStringValue(repeat);
618  NS_ENSURE_SUCCESS(rv, rv);
619 
620  if(repeat.IsEmpty()) {
621  rv = mDataRemotePlaylistRepeat->SetIntValue(
623  NS_ENSURE_SUCCESS(rv, rv);
624  }
625 
626  // Shuffle disable
628  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
629  NS_ENSURE_SUCCESS(rv, rv);
632  nullString);
633  NS_ENSURE_SUCCESS(rv, rv);
634  rv = mDataRemotePlaylistShuffleDisabled->SetBoolValue(PR_FALSE);
635  NS_ENSURE_SUCCESS(rv, rv);
636 
637  // Repeat disable
639  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
640  NS_ENSURE_SUCCESS(rv, rv);
643  nullString);
644  NS_ENSURE_SUCCESS(rv, rv);
645  rv = mDataRemotePlaylistRepeatDisabled->SetBoolValue(PR_FALSE);
646  NS_ENSURE_SUCCESS(rv, rv);
647 
648  // Previous disable
650  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
651  NS_ENSURE_SUCCESS(rv, rv);
654  nullString);
655  NS_ENSURE_SUCCESS(rv, rv);
656  rv = mDataRemotePlaylistPreviousDisabled->SetBoolValue(PR_FALSE);
657  NS_ENSURE_SUCCESS(rv, rv);
658 
659  // Next disable
661  do_CreateInstance("@songbirdnest.com/Songbird/DataRemote;1", &rv);
662  NS_ENSURE_SUCCESS(rv, rv);
665  nullString);
666  NS_ENSURE_SUCCESS(rv, rv);
667  rv = mDataRemotePlaylistNextDisabled->SetBoolValue(PR_FALSE);
668  NS_ENSURE_SUCCESS(rv, rv);
669 
670  return NS_OK;
671 }
672 
673 nsresult
675 {
676  //
677  // Faceplate DataRemotes
678  //
679  nsresult rv;
680 
682  rv = mDataRemoteFaceplateBuffering->Unbind();
683  NS_ENSURE_SUCCESS(rv, rv);
684  }
685 
687  rv = mDataRemoteFaceplatePlaying->Unbind();
688  NS_ENSURE_SUCCESS(rv, rv);
689  }
690 
692  rv = mDataRemoteFaceplatePaused->Unbind();
693  NS_ENSURE_SUCCESS(rv, rv);
694  }
695 
697  rv = mDataRemoteFaceplateSeenPlaying->Unbind();
698  NS_ENSURE_SUCCESS(rv, rv);
699  }
700 
702  rv = mDataRemoteFaceplateURL->Unbind();
703  NS_ENSURE_SUCCESS(rv, rv);
704  }
705 
707  rv = mDataRemoteFaceplateVolume->Unbind();
708  NS_ENSURE_SUCCESS(rv, rv);
709  }
710 
712  rv = mDataRemoteFaceplateMute->Unbind();
713  NS_ENSURE_SUCCESS(rv, rv);
714  }
715 
716  //
717  // Metadata DataRemotes
718  //
719 
721  rv = mDataRemoteMetadataAlbum->Unbind();
722  NS_ENSURE_SUCCESS(rv, rv);
723  }
724 
726  rv = mDataRemoteMetadataArtist->Unbind();
727  NS_ENSURE_SUCCESS(rv, rv);
728  }
729 
731  rv = mDataRemoteMetadataGenre->Unbind();
732  NS_ENSURE_SUCCESS(rv, rv);
733  }
734 
736  rv = mDataRemoteMetadataTitle->Unbind();
737  NS_ENSURE_SUCCESS(rv, rv);
738  }
739 
741  rv = mDataRemoteMetadataDuration->Unbind();
742  NS_ENSURE_SUCCESS(rv, rv);
743  }
744 
746  rv = mDataRemoteMetadataDurationStr->Unbind();
747  NS_ENSURE_SUCCESS(rv, rv);
748  }
749 
751  rv = mDataRemoteMetadataPosition->Unbind();
752  NS_ENSURE_SUCCESS(rv, rv);
753  }
754 
756  rv = mDataRemoteMetadataPositionStr->Unbind();
757  NS_ENSURE_SUCCESS(rv, rv);
758  }
759 
761  rv = mDataRemoteMetadataRemainingStr->Unbind();
762  NS_ENSURE_SUCCESS(rv, rv);
763  }
764 
766  rv = mDataRemoteMetadataURL->Unbind();
767  NS_ENSURE_SUCCESS(rv, rv);
768  }
769 
771  rv = mDataRemoteMetadataImageURL->Unbind();
772  NS_ENSURE_SUCCESS(rv, rv);
773  }
774 
775  //
776  // Playlist DataRemotes
777  //
778 
780  rv = mDataRemotePlaylistShuffle->Unbind();
781  NS_ENSURE_SUCCESS(rv, rv);
782  }
783 
785  rv = mDataRemotePlaylistRepeat->Unbind();
786  NS_ENSURE_SUCCESS(rv, rv);
787  }
788 
790  rv = mDataRemotePlaylistShuffleDisabled->Unbind();
791  NS_ENSURE_SUCCESS(rv, rv);
792  }
793 
795  rv = mDataRemotePlaylistRepeatDisabled->Unbind();
796  NS_ENSURE_SUCCESS(rv, rv);
797  }
798 
801  NS_ENSURE_SUCCESS(rv, rv);
802  }
803 
805  rv = mDataRemotePlaylistNextDisabled->Unbind();
806  NS_ENSURE_SUCCESS(rv, rv);
807  }
808 
809  return NS_OK;
810 }
811 
812 nsresult
814 {
815  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
816 
817  nsAutoMonitor mon(mMonitor);
818 
819  PRBool paused = PR_FALSE;
820  PRBool playing = PR_FALSE;
821 
824  playing = PR_TRUE;
825  }
827  paused = PR_TRUE;
828  }
829 
830  nsresult rv = mDataRemoteFaceplatePaused->SetBoolValue(paused);
831  NS_ENSURE_SUCCESS(rv, rv);
832 
833  rv = mDataRemoteFaceplatePlaying->SetBoolValue(playing);
834  NS_ENSURE_SUCCESS(rv, rv);
835 
836  return NS_OK;
837 }
838 
839 nsresult
841 {
842  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
843 
844  NS_ENSURE_TRUE(mPlaybackControl, NS_OK);
845 
846  nsString positionStr;
847  nsresult rv = EmitMillisecondsToTimeString(aPosition, positionStr);
848  NS_ENSURE_SUCCESS(rv, rv);
849 
850  nsAutoMonitor mon(mMonitor);
851 
852  rv = mDataRemoteMetadataPosition->SetIntValue(aPosition);
853  NS_ENSURE_SUCCESS(rv, rv);
854 
855  rv = mDataRemoteMetadataPositionStr->SetStringValue(positionStr);
856  NS_ENSURE_SUCCESS(rv, rv);
857 
858  PRUint64 duration;
859  rv = mPlaybackControl->GetDuration(&duration);
860  NS_ENSURE_SUCCESS(rv, rv);
861 
862  nsString remainingStr;
863  PRInt64 remaining = 0;
864 
865  if(duration > aPosition)
866  remaining = duration - aPosition;
867 
868  rv = EmitMillisecondsToTimeString(remaining, remainingStr, true);
869  NS_ENSURE_SUCCESS(rv, rv);
870 
871  rv = mDataRemoteMetadataRemainingStr->SetStringValue(remainingStr);
872  NS_ENSURE_SUCCESS(rv, rv);
873 
874  return NS_OK;
875 }
876 
877 nsresult
879 {
880  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
881 
882  if(!mPlaybackControl) {
883  return NS_OK;
884  }
885 
886  PRUint64 duration = aDuration;
887  nsresult rv = mDataRemoteMetadataDuration->SetIntValue(duration);
888  NS_ENSURE_SUCCESS(rv, rv);
889 
890  nsString str;
891  rv = EmitMillisecondsToTimeString(duration, str);
892  NS_ENSURE_SUCCESS(rv, rv);
893 
894  nsAutoMonitor mon(mMonitor);
895 
896  rv = mDataRemoteMetadataDurationStr->SetStringValue(str);
897  NS_ENSURE_SUCCESS(rv, rv);
898 
899  return NS_OK;
900 }
901 
902 nsresult
904 {
905  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
906  NS_ENSURE_ARG_POINTER(aURI);
907 
908  nsCString spec;
909  nsresult rv = aURI->GetSpec(spec);
910  NS_ENSURE_SUCCESS(rv, rv);
911 
912  nsAutoMonitor mon(mMonitor);
913 
914  NS_ConvertUTF8toUTF16 wideSpec(spec);
915  rv = mDataRemoteFaceplateURL->SetStringValue(wideSpec);
916  NS_ENSURE_SUCCESS(rv, rv);
917 
918  rv = mDataRemoteMetadataURL->SetStringValue(wideSpec);
919  NS_ENSURE_SUCCESS(rv, rv);
920 
921  return NS_OK;
922 }
923 
924 nsresult
926 {
927  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
928 
929  PRBool shuffle = PR_FALSE;
931  shuffle = PR_TRUE;
932  }
933 
934  nsAutoMonitor mon(mMonitor);
935 
936  nsresult rv = mDataRemotePlaylistShuffle->SetBoolValue(shuffle);
937  NS_ENSURE_SUCCESS(rv, rv);
938 
939  return NS_OK;
940 }
941 
942 nsresult
944 {
945  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
946 
947  nsAutoMonitor mon(mMonitor);
948 
949  nsresult rv = mDataRemotePlaylistRepeat->SetIntValue(aRepeatMode);
950  NS_ENSURE_SUCCESS(rv, rv);
951 
952  return NS_OK;
953 }
954 
955 nsresult
957 {
958 
959  PRBool isPlayingVideo;
960  nsresult rv = mDataRemoteFaceplatePlayingVideo->GetBoolValue(&isPlayingVideo);
961  NS_ENSURE_SUCCESS(rv, rv);
962 
963  if (isPlayingVideo) {
965  NS_ENSURE_SUCCESS(rv, rv);
966 
967  rv = mDataRemoteFaceplatePlayingVideo->SetBoolValue(PR_FALSE);
968  NS_ENSURE_SUCCESS(rv, rv);
969  }
970 
971  return NS_OK;
972 }
973 
974 nsresult
976 {
977  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
978  NS_ENSURE_ARG_POINTER(aEvent);
979 
980  nsCOMPtr<nsIVariant> variant;
981  nsresult rv = aEvent->GetData(getter_AddRefs(variant));
982  NS_ENSURE_SUCCESS(rv, rv);
983 
984  PRFloat64 volume;
985  rv = variant->GetAsDouble(&volume);
986  NS_ENSURE_SUCCESS(rv, rv);
987 
988  rv = UpdateVolumeDataRemote(volume);
989  NS_ENSURE_SUCCESS(rv, rv);
990 
991  return NS_OK;
992 }
993 
994 nsresult
996 {
997  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
998 
999  nsAutoMonitor mon(mMonitor);
1000 
1001  nsCString volume;
1002  SB_ConvertFloatVolToJSStringValue(aVolume, volume);
1003 
1004  NS_ConvertUTF8toUTF16 volumeStr(volume);
1005  nsresult rv = mDataRemoteFaceplateVolume->SetStringValue(volumeStr);
1006  NS_ENSURE_SUCCESS(rv, rv);
1007 
1008  return NS_OK;
1009 }
1010 
1011 nsresult
1013 {
1014  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1015  NS_ENSURE_ARG_POINTER(aEvent);
1016 
1017  nsCOMPtr<nsIVariant> variant;
1018  nsresult rv = aEvent->GetData(getter_AddRefs(variant));
1019  NS_ENSURE_SUCCESS(rv, rv);
1020 
1021  PRBool muted = PR_FALSE;
1022  rv = variant->GetAsBool(&muted);
1023  NS_ENSURE_SUCCESS(rv, rv);
1024 
1025  rv = UpdateMuteDataRemote(muted);
1026  NS_ENSURE_SUCCESS(rv, rv);
1027 
1028  return NS_OK;
1029 }
1030 
1031 nsresult
1033 {
1034  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1035 
1036  nsAutoMonitor mon(mMonitor);
1037 
1038  nsresult rv = mDataRemoteFaceplateMute->SetBoolValue(aMuted);
1039  NS_ENSURE_SUCCESS(rv, rv);
1040 
1041  return NS_OK;
1042 }
1043 
1044 nsresult
1046 {
1047  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1048  NS_ENSURE_ARG_POINTER(aEvent);
1049 
1050  nsCOMPtr<nsIVariant> variant;
1051  nsresult rv = aEvent->GetData(getter_AddRefs(variant));
1052  NS_ENSURE_SUCCESS(rv, rv);
1053 
1054  nsCOMPtr<nsISupports> supports;
1055  rv = variant->GetAsISupports(getter_AddRefs(supports));
1056  NS_ENSURE_SUCCESS(rv, rv);
1057 
1058  nsCOMPtr<sbIPropertyArray> propertyArray =
1059  do_QueryInterface(supports, &rv);
1060  NS_ENSURE_SUCCESS(rv, rv);
1061 
1062  PRUint32 length = 0;
1063  rv = propertyArray->GetLength(&length);
1064  NS_ENSURE_SUCCESS(rv, rv);
1065 
1066  nsCOMPtr<sbIProperty> property;
1067  for(PRUint32 current = 0; current < length; ++current) {
1068  rv = propertyArray->GetPropertyAt(current, getter_AddRefs(property));
1069  NS_ENSURE_SUCCESS(rv, rv);
1070 
1071  nsString id, value;
1072  rv = property->GetId(id);
1073  NS_ENSURE_SUCCESS(rv, rv);
1074 
1075  rv = property->GetValue(value);
1076  NS_ENSURE_SUCCESS(rv, rv);
1077 
1078  rv = SetMetadataDataRemote(id, value);
1079  NS_ENSURE_SUCCESS(rv, rv);
1080  }
1081 
1082  return NS_OK;
1083 }
1084 
1085 nsresult
1087  const nsAString &aValue)
1088 {
1089  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1090 
1091  LOG(("[sbMediacoreSequencer] - SetMetadataDataRemote: Id '%s', Value '%s'",
1092  NS_ConvertUTF16toUTF8(aId).BeginReading(),
1093  NS_ConvertUTF16toUTF8(aValue).BeginReading()));
1094 
1095  if(!mCurrentItem) {
1096  return NS_OK;
1097  }
1098 
1099  //
1100  // For local files, we want to keep the existing property rather than
1101  // overriding it here if we successfully imported metadata in the first
1102  // place. As a proxy for "successfully imported metadata", we check if
1103  // the artist is non-empty.
1104  //
1105  // We allow overriding for non-file URIs so that streams that update
1106  // their metadata periodically can continue to do so.
1107  //
1108  nsString artistName;
1109  nsresult rv = mCurrentItem->GetProperty(
1110  NS_LITERAL_STRING(SB_PROPERTY_ARTISTNAME), artistName);
1111  NS_ENSURE_SUCCESS(rv, rv);
1112 
1113  nsCOMPtr<nsIURI> uri;
1114  rv = mCurrentItem->GetContentSrc(getter_AddRefs(uri));
1115  NS_ENSURE_SUCCESS(rv, rv);
1116 
1117  nsCString scheme;
1118  rv = uri->GetScheme(scheme);
1119  NS_ENSURE_SUCCESS(rv, rv);
1120 
1121  if (scheme.EqualsLiteral("file") && !artistName.IsEmpty())
1122  return NS_OK;
1123 
1124  nsCOMPtr<sbIDataRemote> remote;
1125  if(aId.EqualsLiteral(SB_PROPERTY_ALBUMNAME)) {
1126  remote = mDataRemoteMetadataAlbum;
1127  }
1128  else if(aId.EqualsLiteral(SB_PROPERTY_ARTISTNAME)) {
1129  remote = mDataRemoteMetadataArtist;
1130  }
1131  else if(aId.EqualsLiteral(SB_PROPERTY_GENRE)) {
1132  remote = mDataRemoteMetadataGenre;
1133  }
1134  else if(aId.EqualsLiteral(SB_PROPERTY_TRACKNAME)) {
1135  remote = mDataRemoteMetadataTitle;
1136  }
1137  else if(aId.EqualsLiteral(SB_PROPERTY_PRIMARYIMAGEURL)) {
1138  remote = mDataRemoteMetadataImageURL;
1139  }
1140 
1141  if(remote) {
1142  nsresult rv = remote->SetStringValue(aValue);
1143  NS_ENSURE_SUCCESS(rv, rv);
1144  }
1145 
1146  return NS_OK;
1147 }
1148 
1149 PRBool
1151  const nsAString &aPropName)
1152 {
1153  PRUint32 length = 0;
1154  nsresult rv = aPropArray->GetLength(&length);
1155  NS_ENSURE_SUCCESS(rv, PR_FALSE);
1156 
1157  nsCOMPtr<sbIProperty> property;
1158  for(PRUint32 current = 0; current < length; ++current) {
1159  rv = aPropArray->GetPropertyAt(current, getter_AddRefs(property));
1160  NS_ENSURE_SUCCESS(rv, PR_FALSE);
1161 
1162  nsString id;
1163  rv = property->GetId(id);
1164  NS_ENSURE_SUCCESS(rv, PR_FALSE);
1165 
1166  if(id.Equals(aPropName)) {
1167  return PR_TRUE;
1168  }
1169  }
1170 
1171  return PR_FALSE;
1172 }
1173 
1174 /* Set the metadata data remotes from the properties on aItem.
1175  * If aPropertiesChanges is non-null, only set the data remotes that rely on
1176  * the changed properties.
1177  */
1178 nsresult
1180  sbIMediaItem *aItem,
1181  sbIPropertyArray *aPropertiesChanged)
1182 {
1183  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1184  NS_ENSURE_ARG_POINTER(aItem);
1185 
1186  nsString albumName, artistName, genre, trackName, imageURL;
1187  nsresult rv;
1188 
1189  if(!aPropertiesChanged ||
1190  IsPropertyInPropertyArray(aPropertiesChanged,
1191  NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME)))
1192  {
1193  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME),
1194  albumName);
1195  NS_ENSURE_SUCCESS(rv, rv);
1196 
1197  rv = mDataRemoteMetadataAlbum->SetStringValue(albumName);
1198  NS_ENSURE_SUCCESS(rv, rv);
1199  }
1200 
1201  if(!aPropertiesChanged ||
1202  IsPropertyInPropertyArray(aPropertiesChanged,
1203  NS_LITERAL_STRING(SB_PROPERTY_ARTISTNAME)))
1204  {
1205  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ARTISTNAME),
1206  artistName);
1207  NS_ENSURE_SUCCESS(rv, rv);
1208 
1209  rv = mDataRemoteMetadataArtist->SetStringValue(artistName);
1210  NS_ENSURE_SUCCESS(rv, rv);
1211  }
1212 
1213  if(!aPropertiesChanged ||
1214  IsPropertyInPropertyArray(aPropertiesChanged,
1215  NS_LITERAL_STRING(SB_PROPERTY_GENRE)))
1216  {
1217  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_GENRE), genre);
1218  NS_ENSURE_SUCCESS(rv, rv);
1219 
1220  rv = mDataRemoteMetadataGenre->SetStringValue(genre);
1221  NS_ENSURE_SUCCESS(rv, rv);
1222  }
1223 
1224  if(!aPropertiesChanged ||
1225  IsPropertyInPropertyArray(aPropertiesChanged,
1226  NS_LITERAL_STRING(SB_PROPERTY_TRACKNAME)))
1227  {
1228  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNAME),
1229  trackName);
1230  NS_ENSURE_SUCCESS(rv, rv);
1231 
1232  rv = mDataRemoteMetadataTitle->SetStringValue(trackName);
1233  NS_ENSURE_SUCCESS(rv, rv);
1234  }
1235 
1236  if(!aPropertiesChanged ||
1237  IsPropertyInPropertyArray(aPropertiesChanged,
1238  NS_LITERAL_STRING(SB_PROPERTY_PRIMARYIMAGEURL)))
1239  {
1240  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_PRIMARYIMAGEURL),
1241  imageURL);
1242  NS_ENSURE_SUCCESS(rv, rv);
1243 
1244  rv = mDataRemoteMetadataImageURL->SetStringValue(imageURL);
1245  NS_ENSURE_SUCCESS(rv, rv);
1246  }
1247 
1248  return NS_OK;
1249 }
1250 
1251 nsresult
1253  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1254 
1255  nsresult rv = mDataRemoteMetadataAlbum->SetStringValue(EmptyString());
1256  NS_ENSURE_SUCCESS(rv, rv);
1257 
1258  rv = mDataRemoteMetadataArtist->SetStringValue(EmptyString());
1259  NS_ENSURE_SUCCESS(rv, rv);
1260 
1261  rv = mDataRemoteMetadataGenre->SetStringValue(EmptyString());
1262  NS_ENSURE_SUCCESS(rv, rv);
1263 
1264  rv = mDataRemoteMetadataTitle->SetStringValue(EmptyString());
1265  NS_ENSURE_SUCCESS(rv, rv);
1266 
1267  rv = mDataRemoteMetadataImageURL->SetStringValue(EmptyString());
1268  NS_ENSURE_SUCCESS(rv, rv);
1269 
1270  rv = UpdatePositionDataRemotes(0);
1271  NS_ENSURE_SUCCESS(rv, rv);
1272 
1273  rv = UpdateDurationDataRemotes(0);
1274  NS_ENSURE_SUCCESS(rv, rv);
1275 
1276  return NS_OK;
1277 }
1278 
1279 nsresult
1281 {
1282  if(mCurrentItem) {
1283  NS_NAMED_LITERAL_STRING(PROPERTY_DURATION, SB_PROPERTY_DURATION);
1284  nsString strDuration;
1285  nsresult rv = mCurrentItem->GetProperty(PROPERTY_DURATION,
1286  strDuration);
1287  NS_ENSURE_SUCCESS(rv, rv);
1288 
1289  PRUint64 itemDuration = 0;
1290 
1291  // if there was a duration set, convert it.
1292  if (!strDuration.IsEmpty()) {
1293  itemDuration = nsString_ToUint64(strDuration, &rv);
1294  NS_ENSURE_SUCCESS(rv, rv);
1295  }
1296 
1297  itemDuration /= PR_USEC_PER_MSEC;
1298 
1299  if(aDuration && itemDuration != aDuration) {
1300  sbScopedBoolToggle doNotRecalculate(&mNoRecalculate);
1301  sbAutoString strNewDuration(aDuration * PR_USEC_PER_MSEC);
1302  rv = mCurrentItem->SetProperty(PROPERTY_DURATION, strNewDuration);
1303  NS_ENSURE_SUCCESS(rv, rv);
1304  }
1305  }
1306  return NS_OK;
1307 }
1308 
1309 nsresult
1311 {
1312  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1313 
1314  nsresult rv;
1315 
1319  // Grip.
1320  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl = mPlaybackControl;
1321  aMonitor.Exit();
1322  rv = playbackControl->Stop();
1323  NS_ASSERTION(NS_SUCCEEDED(rv), "Stop failed at end of sequence.");
1324  aMonitor.Enter();
1325  }
1326 
1328 
1329  rv = StopSequenceProcessor();
1330  NS_ENSURE_SUCCESS(rv, rv);
1331 
1333  NS_ENSURE_SUCCESS(rv, rv);
1334 
1335  if(mSeenPlaying) {
1336  mSeenPlaying = PR_FALSE;
1337 
1338  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_FALSE);
1339  NS_ENSURE_SUCCESS(rv, rv);
1340  }
1341 
1342  return NS_OK;
1343 }
1344 
1345 nsresult
1347 {
1348  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1349  NS_ENSURE_ARG_POINTER(aEvent);
1350 
1351  nsAutoMonitor mon(mMonitor);
1352  mErrorCount++;
1353 
1354  if(mIsWaitingForPlayback) {
1355  mIsWaitingForPlayback = PR_FALSE;
1356  }
1357 
1358  nsresult rv;
1360  // Too many subsequent errors, stop
1361  rv = StopPlaybackHelper(mon);
1362  NS_ENSURE_SUCCESS(rv, rv);
1363  }
1364  else {
1365  if (mCoreWillHandleNext) {
1366  // The core has requested handling the next item, then given us an error.
1367  // Assume the error is about the next item - thus, we should skip to two
1368  // items ahead.
1369  // This call to Next() (while mCoreWillHandleNext is set) will just cause
1370  // the position tracking to update - we won't try to play it again this
1371  // time.
1372  rv = Next(PR_TRUE);
1373  NS_ENSURE_SUCCESS(rv, rv);
1374  }
1375 
1376  mCoreWillHandleNext = PR_FALSE;
1377 
1378  nsCOMPtr<sbIMediaItem> mediaItem;
1379  rv = GetCurrentItem(getter_AddRefs(mediaItem));
1380  NS_ENSURE_SUCCESS(rv, rv);
1381 
1382  nsString contentType;
1383  // We might not have a media item here (if we don't have a view), so just
1384  // stop playback.
1385  if (mediaItem) {
1386  rv = mediaItem->GetContentType(contentType);
1387  NS_ENSURE_SUCCESS(rv, rv);
1388  }
1389 
1390  // Pause the sequencer if playback error happens to video, or if we no
1391  // longer have a current item.
1392  if (!contentType.Equals(NS_LITERAL_STRING("video"))) {
1393  rv = Next(PR_TRUE);
1394  NS_ENSURE_SUCCESS(rv, rv);
1395  }
1396  else {
1397  rv = StopPlaybackHelper(mon);
1398  NS_ENSURE_SUCCESS(rv, rv);
1399  }
1400  }
1401  mon.Exit();
1402 
1403  nsCOMPtr<sbIMediacoreError> error;
1404  rv = aEvent->GetError(getter_AddRefs(error));
1405  NS_ENSURE_SUCCESS(rv, rv);
1406 
1407  // If there's an error object, we'll show the contents of it to the user
1408  if(error) {
1409  nsCOMPtr<sbIMediacoreErrorHandler> errorHandler =
1410  do_GetService("@songbirdnest.com/Songbird/MediacoreErrorHandler;1", &rv);
1411  NS_ENSURE_SUCCESS(rv, rv);
1412 
1413  rv = errorHandler->ProcessError(error);
1414  NS_ENSURE_SUCCESS(rv, rv);
1415  }
1416 
1417  return NS_OK;
1418 }
1419 
1420 nsresult
1421 sbMediacoreSequencer::RecalculateSequence(PRInt64 *aViewPosition /*= nsnull*/)
1422 {
1423  LOG(("[%s] Recalculating Sequence", __FUNCTION__));
1424 
1425  nsAutoMonitor mon(mMonitor);
1426 
1427  if(!mView) {
1428  return NS_OK;
1429  }
1430 
1431  mSequence.clear();
1432  mViewIndexToSequenceIndex.clear();
1433 
1434  PRUint32 length = 0;
1435  nsresult rv = mView->GetLength(&length);
1436  NS_ENSURE_SUCCESS(rv, rv);
1437 
1438  mPosition = 0;
1439  mSequence.reserve(length);
1440 
1441  // ensure view position is inside the bounds of the view.
1442  if(aViewPosition &&
1443  ((*aViewPosition >= length) ||
1444  (*aViewPosition < sbIMediacoreSequencer::AUTO_PICK_INDEX))) {
1445  *aViewPosition = 0;
1446  }
1447 
1448  switch(mMode) {
1450  {
1451  // Generate forward sequence
1452  for(PRUint32 i = 0; i < length; ++i) {
1453  mSequence.push_back(i);
1455  }
1456 
1457  if(aViewPosition &&
1458  *aViewPosition != sbIMediacoreSequencer::AUTO_PICK_INDEX) {
1459  mPosition = (PRUint32)(*aViewPosition);
1460  }
1461  }
1462  break;
1464  {
1465  // Generate reverse sequence
1466  PRUint32 j = 0;
1467  for(PRUint32 i = length - 1; i >= 0; --i, ++j) {
1468  mSequence.push_back(i);
1470  }
1471 
1472  if(aViewPosition &&
1473  *aViewPosition != sbIMediacoreSequencer::AUTO_PICK_INDEX) {
1474  mPosition = (PRUint32)(length - *aViewPosition);
1475  }
1476  }
1477  break;
1479  {
1480  NS_ENSURE_TRUE(mShuffleGenerator, NS_ERROR_UNEXPECTED);
1481 
1482  PRUint32 sequenceLength = 0;
1483  PRUint32 *sequence = nsnull;
1484 
1485  rv = mShuffleGenerator->OnGenerateSequence(mView,
1486  &sequenceLength,
1487  &sequence);
1488  NS_ENSURE_SUCCESS(rv, rv);
1489 
1490  for(PRUint32 i = 0; i < sequenceLength; ++i) {
1491  mSequence.push_back(sequence[i]);
1492  mViewIndexToSequenceIndex[sequence[i]] = i;
1493 
1494  if(aViewPosition &&
1495  *aViewPosition != sbIMediacoreSequencer::AUTO_PICK_INDEX &&
1496  *aViewPosition == sequence[i]) {
1497  // Swap the first position item with the item that was selected by the
1498  // user to play first.
1499  PRUint32 viewIndex = mSequence[0];
1500  mSequence[0] = mSequence[i];
1501  mSequence[i] = viewIndex;
1502 
1503  PRUint32 sequenceIndex = mViewIndexToSequenceIndex[viewIndex];
1505  mViewIndexToSequenceIndex[mSequence[0]] = sequenceIndex;
1506  }
1507  }
1508 
1509  NS_Free(sequence);
1510  }
1511  break;
1513  {
1514  NS_ENSURE_TRUE(mCustomGenerator, NS_ERROR_UNEXPECTED);
1515 
1516  PRUint32 sequenceLength = 0;
1517  PRUint32 *sequence = nsnull;
1518 
1519  rv = mCustomGenerator->OnGenerateSequence(mView,
1520  &sequenceLength,
1521  &sequence);
1522  NS_ENSURE_SUCCESS(rv, rv);
1523 
1524  for(PRUint32 i = 0; i < sequenceLength; ++i) {
1525  mSequence.push_back(sequence[i]);
1526  mViewIndexToSequenceIndex[sequence[i]] = i;
1527 
1528  if(aViewPosition &&
1529  *aViewPosition != sbIMediacoreSequencer::AUTO_PICK_INDEX &&
1530  *aViewPosition == sequence[i]) {
1531  // Match the sequence position to the item that is selected
1532  mPosition = i;
1533  }
1534  }
1535 
1536  NS_Free(sequence);
1537  }
1538  break;
1539  }
1540 
1541  if(mSequence.size()) {
1543  }
1544  else {
1545  mViewPosition = 0;
1546  }
1547 
1548  // Fire sequence changed event
1549  nsCOMPtr<nsIArray> newSequence;
1550  rv = GetCurrentSequence(getter_AddRefs(newSequence));
1551  NS_ENSURE_SUCCESS(rv, rv);
1552 
1553  nsCOMPtr<nsIVariant> variant = sbNewVariant(newSequence).get();
1554  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
1555 
1556  nsCOMPtr<sbIMediacoreEvent> event;
1558  nsnull,
1559  variant,
1560  mCore,
1561  getter_AddRefs(event));
1562  NS_ENSURE_SUCCESS(rv, rv);
1563 
1564  rv = DispatchMediacoreEvent(event);
1565  NS_ENSURE_SUCCESS(rv, rv);
1566 
1567  return NS_OK;
1568 }
1569 
1570 nsresult
1572  PRUint32 aPosition,
1573  sbIMediaItem **aItem)
1574 {
1575  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1576  NS_ENSURE_ARG_POINTER(aItem);
1577 
1578  nsAutoMonitor mon(mMonitor);
1579 
1580  PRUint32 length = mSequence.size();
1581  NS_ENSURE_TRUE(aPosition < length, NS_ERROR_INVALID_ARG);
1582 
1583  nsCOMPtr<sbIMediaItem> item;
1584  nsresult rv = mView->GetItemByIndex(aSequence[aPosition],
1585  getter_AddRefs(item));
1586  NS_ENSURE_SUCCESS(rv, rv);
1587 
1588  item.forget(aItem);
1589 
1590  return NS_OK;
1591 }
1592 
1593 nsresult
1595 {
1596  nsAutoMonitor mon(mMonitor);
1597 
1598  nsresult rv = ResetMetadataDataRemotes();
1599  NS_ENSURE_SUCCESS(rv, rv);
1600 
1601  // if the current core requested handling of the next item, we have nothing
1602  // to do here but reset the flag.
1603  if(mCoreWillHandleNext) {
1604  mon.Exit();
1605 
1606  rv = CoreHandleNextSetup();
1607  if(rv == NS_ERROR_ABORT) {
1608  NS_WARNING("Someone aborted playback of the next track.");
1609  return NS_OK;
1610  }
1611  NS_ENSURE_SUCCESS(rv, rv);
1612 
1613  return NS_OK;
1614  }
1615 
1616  mon.Exit();
1617 
1618  rv = Setup();
1619  if(rv == NS_ERROR_ABORT) {
1620  NS_WARNING("Someone aborted playback of the next track.");
1621  return NS_OK;
1622  }
1623  NS_ENSURE_SUCCESS(rv, rv);
1624 
1625  mon.Enter();
1626 
1629 
1631  mIsWaitingForPlayback = PR_TRUE;
1632 
1634  NS_ENSURE_SUCCESS(rv, rv);
1635 
1636  mon.Exit();
1637 
1638  rv = StartPlayback();
1639  }
1641  mon.Exit();
1642  rv = mPlaybackControl->Pause();
1643  }
1644 
1645  if(NS_FAILED(rv)) {
1646  mon.Enter();
1648  mIsWaitingForPlayback = PR_FALSE;
1649 
1651  NS_ENSURE_SUCCESS(rv, rv);
1652 
1653  return rv;
1654  }
1655 
1656  return NS_OK;
1657 }
1658 
1659 nsresult
1660 sbMediacoreSequencer::Setup(nsIURI *aURI /*= nsnull*/)
1661 {
1662  nsAutoMonitor mon(mMonitor);
1663 
1664  nsCOMPtr<nsIURI> uri;
1665  nsCOMPtr<sbIMediaItem> item;
1666  nsCOMPtr<sbIMediaItem> lastItem = mCurrentItem;
1667 
1668  nsresult rv = NS_ERROR_UNEXPECTED;
1669 
1670  if(!aURI) {
1671  rv = GetItem(mSequence, mPosition, getter_AddRefs(item));
1672  NS_ENSURE_SUCCESS(rv, rv);
1673 
1675 
1676  rv = mView->GetViewItemUIDForIndex(mCurrentItemIndex, mCurrentItemUID);
1677  NS_ENSURE_SUCCESS(rv, rv);
1678 
1679  mCurrentItem = item;
1680 
1681  rv = item->GetContentSrc(getter_AddRefs(uri));
1682  NS_ENSURE_SUCCESS(rv, rv);
1683  }
1684  else {
1685  uri = aURI;
1686 
1687  mCurrentItem = nsnull;
1688  mCurrentItemIndex = 0;
1689  }
1690 
1691  nsCOMPtr<sbIMediacoreVoting> voting =
1692  do_QueryReferent(mMediacoreManager, &rv);
1693  NS_ENSURE_SUCCESS(rv, rv);
1694 
1695  NS_ENSURE_TRUE(voting, NS_ERROR_UNEXPECTED);
1696 
1697  // Voting calls into mediacores; we don't want to hold the monitor while we
1698  // do that.
1699  mon.Exit();
1700 
1701  nsCOMPtr<sbIMediacoreVotingChain> votingChain;
1702  rv = voting->VoteWithURI(uri, getter_AddRefs(votingChain));
1703  NS_ENSURE_SUCCESS(rv, rv);
1704 
1705  PRBool validChain = PR_FALSE;
1706  rv = votingChain->GetValid(&validChain);
1707  NS_ENSURE_SUCCESS(rv, rv);
1708 
1709  // Not a valid chain, we'll have to skip this item.
1710  if(!validChain) {
1711  // XXXAus: Skip item later, for now fail.
1712  return NS_ERROR_UNEXPECTED;
1713  }
1714 
1715  nsCOMPtr<nsIArray> chain;
1716  rv = votingChain->GetMediacoreChain(getter_AddRefs(chain));
1717  NS_ENSURE_SUCCESS(rv, rv);
1718 
1719  // Reacquire the monitor now that we're done with voting.
1720  mon.Enter();
1721 
1722  mChain = chain;
1723  mChainIndex = 0;
1724 
1725  // Remove listener from old core.
1726  if(mCore) {
1727  // But only remove it if we're not going to use the same core
1728  // to play again.
1729  nsCOMPtr<sbIMediacore> nextCore =
1730  do_QueryElementAt(chain, mChainIndex, &rv);
1731  NS_ENSURE_SUCCESS(rv, rv);
1732 
1733  if(mCore != nextCore) {
1734  nsCOMPtr<sbIMediacoreEventTarget> eventTarget =
1735  do_QueryInterface(mCore, &rv);
1736 
1737  rv = eventTarget->RemoveListener(this);
1738  NS_ENSURE_SUCCESS(rv, rv);
1739  }
1740 
1744 
1745  if(mCore == nextCore) {
1746  // Remember the fact that we called stop so we ignore the stop
1747  // event coming from the core.
1748  mStopTriggeredBySequencer = PR_TRUE;
1749  }
1750 
1751  // Grip.
1752  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl = mPlaybackControl;
1753  mon.Exit();
1754 
1755  // If we played an Item, update it. If we played an url (no Item in Library), we skip this part.
1756  if (lastItem){
1757  rv = UpdateLastPositionProperty(lastItem, nsnull);
1758  NS_ENSURE_SUCCESS(rv, rv);
1759  }
1760 
1761  rv = playbackControl->Stop();
1762  NS_ASSERTION(NS_SUCCEEDED(rv),
1763  "Stop returned failure. Attempting to recover.");
1764 
1765  mon.Enter();
1766  }
1767  }
1768 
1769  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl =
1770  do_QueryElementAt(chain, mChainIndex, &rv);
1771  NS_ENSURE_SUCCESS(rv, rv);
1772  mPlaybackControl = playbackControl;
1773 
1774  mCore = do_QueryElementAt(chain, mChainIndex, &rv);
1775  NS_ENSURE_SUCCESS(rv, rv);
1776 
1777  // Fire before track change event
1778  if(item) {
1779  nsCOMPtr<nsIVariant> variant = sbNewVariant(item).get();
1780  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
1781 
1782  nsCOMPtr<sbIMediacoreEvent> event;
1784  nsnull,
1785  variant,
1786  mCore,
1787  getter_AddRefs(event));
1788  NS_ENSURE_SUCCESS(rv, rv);
1789 
1790  sbScopedBoolToggle canAbort(&mCanAbort);
1791 
1792  rv = DispatchMediacoreEvent(event);
1793  NS_ENSURE_SUCCESS(rv, rv);
1794 
1795  mon.Exit();
1796 
1797  // Process any pending abort requests
1798  if(HandleAbort()) {
1799  return NS_ERROR_ABORT;
1800  }
1801 
1802  mon.Enter();
1803  }
1804 
1805  // Add listener to new core.
1806  nsCOMPtr<sbIMediacoreEventTarget> eventTarget =
1807  do_QueryInterface(mCore, &rv);
1808  NS_ENSURE_SUCCESS(rv, rv);
1809 
1810  rv = eventTarget->AddListener(this);
1811  NS_ENSURE_SUCCESS(rv, rv);
1812 
1813  rv = mPlaybackControl->SetUri(uri);
1814  NS_ENSURE_SUCCESS(rv, rv);
1815 
1816 #ifdef PR_LOGGING
1817  {
1818  nsCString spec;
1819  rv = uri->GetSpec(spec);
1820  LOG(("[sbMediacoreSequencer] -- Attempting to play %s",
1821  spec.BeginReading()));
1822  }
1823 #endif
1824 
1825  nsCOMPtr<sbPIMediacoreManager> privateMediacoreManager =
1826  do_QueryReferent(mMediacoreManager, &rv);
1827  NS_ENSURE_SUCCESS(rv, rv);
1828 
1829  rv = privateMediacoreManager->SetPrimaryCore(mCore);
1830  NS_ENSURE_SUCCESS(rv, rv);
1831 
1832  rv = mCore->SetSequencer(this);
1833  NS_ENSURE_SUCCESS(rv, rv);
1834 
1835  rv = StartSequenceProcessor();
1836  NS_ENSURE_SUCCESS(rv, rv);
1837 
1838  rv = UpdateURLDataRemotes(uri);
1839  NS_ENSURE_SUCCESS(rv, rv);
1840 
1841  if(item) {
1842  rv = SetMetadataDataRemotesFromItem(item);
1843  NS_ENSURE_SUCCESS(rv, rv);
1844 
1845  // Fire track change event
1846  nsCOMPtr<nsIVariant> variant = sbNewVariant(item).get();
1847  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
1848 
1849  nsCOMPtr<sbIMediacoreEvent> event;
1851  nsnull,
1852  variant,
1853  mCore,
1854  getter_AddRefs(event));
1855  NS_ENSURE_SUCCESS(rv, rv);
1856 
1857  rv = DispatchMediacoreEvent(event, PR_TRUE);
1858  NS_ENSURE_SUCCESS(rv, rv);
1859  }
1860 
1861  return NS_OK;
1862 }
1863 
1864 nsresult
1866 {
1867  nsAutoMonitor mon(mMonitor);
1868 
1869  mCoreWillHandleNext = PR_FALSE;
1870 
1871  // If the current position is valid, get the item at the current position.
1872  // Otherwise, get the current item without modifying the sequencer state.
1873  nsresult rv;
1874  nsCOMPtr<sbIMediaItem> item;
1875  if (!mPositionInvalidated) {
1876  rv = GetItem(mSequence, mPosition, getter_AddRefs(item));
1877  NS_ENSURE_SUCCESS(rv, rv);
1878 
1880 
1881  rv = mView->GetViewItemUIDForIndex(mCurrentItemIndex, mCurrentItemUID);
1882  NS_ENSURE_SUCCESS(rv, rv);
1883 
1884  mCurrentItem = item;
1885  } else {
1886  item = mCurrentItem;
1887  }
1888 
1889  nsCOMPtr<nsIURI> uri;
1890  rv = item->GetContentSrc(getter_AddRefs(uri));
1891  NS_ENSURE_SUCCESS(rv, rv);
1892 
1893  nsCOMPtr<nsIVariant> variant = sbNewVariant(item).get();
1894  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
1895 
1896  nsCOMPtr<sbIMediacoreEvent> event;
1898  nsnull,
1899  variant,
1900  mCore,
1901  getter_AddRefs(event));
1902  NS_ENSURE_SUCCESS(rv, rv);
1903 
1904  // Additional scope to handle 'canAbort' status
1905  {
1906  sbScopedBoolToggle canAbort(&mCanAbort);
1907 
1908  rv = DispatchMediacoreEvent(event);
1909  NS_ENSURE_SUCCESS(rv, rv);
1910 
1911  mon.Exit();
1912 
1913  // Process any pending abort requests
1914  if(HandleAbort()) {
1915  return NS_ERROR_ABORT;
1916  }
1917 
1918  mon.Enter();
1919  }
1920 
1921  rv = UpdateURLDataRemotes(uri);
1922  NS_ENSURE_SUCCESS(rv, rv);
1923 
1924  rv = SetMetadataDataRemotesFromItem(item);
1925  NS_ENSURE_SUCCESS(rv, rv);
1926 
1927  // Fire track change event
1928  variant = sbNewVariant(item).get();
1930  nsnull,
1931  variant,
1932  mCore,
1933  getter_AddRefs(event));
1934  NS_ENSURE_SUCCESS(rv, rv);
1935 
1936  rv = DispatchMediacoreEvent(event);
1937  NS_ENSURE_SUCCESS(rv, rv);
1938 
1939  return NS_OK;
1940 }
1941 
1942 PRBool
1944 {
1945  nsAutoMonitor mon(mMonitor);
1946 
1947  if(mShouldAbort) {
1948  mShouldAbort = PR_FALSE;
1949 
1950  mon.Exit();
1951 
1952  nsresult rv = Stop(PR_TRUE);
1953  NS_ENSURE_SUCCESS(rv, PR_FALSE);
1954 
1955  return PR_TRUE;
1956  }
1957 
1958  return PR_FALSE;
1959 }
1960 
1961 nsresult
1963 {
1964  nsresult rv;
1965 
1966  rv = mDataRemotePlaylistShuffleDisabled->SetBoolValue(PR_FALSE);
1967  NS_ENSURE_SUCCESS(rv, rv);
1968 
1969  rv = mDataRemotePlaylistRepeatDisabled->SetBoolValue(PR_FALSE);
1970  NS_ENSURE_SUCCESS(rv, rv);
1971 
1972  rv = mDataRemotePlaylistPreviousDisabled->SetBoolValue(PR_FALSE);
1973  NS_ENSURE_SUCCESS(rv, rv);
1974 
1975  rv = mDataRemotePlaylistNextDisabled->SetBoolValue(PR_FALSE);
1976  NS_ENSURE_SUCCESS(rv, rv);
1977 
1978  return NS_OK;
1979 }
1980 
1981 nsresult
1983  PRInt64 *aViewPosition /* = nsnull */)
1984 {
1985  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
1986  NS_ENSURE_ARG_POINTER(aView);
1987 
1988  nsAutoMonitor mon(mMonitor);
1989 
1990  // Regardless of what happens here, we'll have a valid position and view
1991  // position after the method returns, so reset the invalidated position flag.
1992  mPositionInvalidated = PR_FALSE;
1993 
1994  PRUint32 viewLength = 0;
1995  nsresult rv = aView->GetLength(&viewLength);
1996  NS_ENSURE_SUCCESS(rv, rv);
1997 
1998  if(mView != aView ||
1999  mSequence.size() != viewLength) {
2000 
2001  // Fire before view change event
2002  nsCOMPtr<nsIVariant> variant = sbNewVariant(aView).get();
2003  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
2004 
2005  nsCOMPtr<sbIMediacoreEvent> event;
2006  rv =
2008  nsnull,
2009  variant,
2010  mCore,
2011  getter_AddRefs(event));
2012  NS_ENSURE_SUCCESS(rv, rv);
2013 
2014  rv = DispatchMediacoreEvent(event);
2015  NS_ENSURE_SUCCESS(rv, rv);
2016 
2017  rv = StopWatchingView();
2018  NS_ENSURE_SUCCESS(rv, rv);
2019 
2020  mView = aView;
2021 
2023  NS_ENSURE_SUCCESS(rv, rv);
2024 
2025  rv = StartWatchingView();
2026  NS_ENSURE_SUCCESS(rv, rv);
2027 
2028  rv = RecalculateSequence(aViewPosition);
2029  NS_ENSURE_SUCCESS(rv, rv);
2030 
2031  // Fire view change event
2033  nsnull,
2034  variant,
2035  mCore,
2036  getter_AddRefs(event));
2037  NS_ENSURE_SUCCESS(rv, rv);
2038 
2039  rv = DispatchMediacoreEvent(event);
2040  NS_ENSURE_SUCCESS(rv, rv);
2041  }
2042  else if(aViewPosition &&
2043  *aViewPosition >= 0 &&
2044  mViewPosition != *aViewPosition &&
2045  mViewIndexToSequenceIndex.size() > *aViewPosition) {
2046  // We check to see if the view position is different than the current view
2047  // position before setting the new view position.
2048  mPosition = mViewIndexToSequenceIndex[(PRUint32)(*aViewPosition)];
2050  }
2051 
2052  return NS_OK;
2053 }
2054 
2055 nsresult
2057 {
2058  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2059 
2060  nsAutoMonitor mon(mMonitor);
2061 
2062  // No view, we're probably playing single items
2063  if(!mView) {
2064  return NS_OK;
2065  }
2066 
2067  if(mWatchingView) {
2068  return NS_OK;
2069  }
2070 
2071  nsresult rv = mView->AddListener(this, PR_FALSE);
2072  NS_ENSURE_SUCCESS(rv, rv);
2073 
2074  rv = mView->GetMediaList(getter_AddRefs(mViewList));
2075  NS_ENSURE_SUCCESS(rv, rv);
2076 
2077  nsCOMPtr<sbILibrary> library = do_QueryInterface(mViewList, &rv);
2078  mViewIsLibrary = NS_SUCCEEDED(rv) ? PR_TRUE : PR_FALSE;
2079 
2080  rv = mViewList->AddListener(this,
2081  PR_FALSE,
2089  nsnull);
2090  NS_ENSURE_SUCCESS(rv, rv);
2091 
2092  if(!mViewIsLibrary) {
2093  nsCOMPtr<sbIMediaItem> item = do_QueryInterface(mViewList, &rv);
2094  NS_ENSURE_SUCCESS(rv, rv);
2095 
2096  rv = item->GetLibrary(getter_AddRefs(library));
2097  NS_ENSURE_SUCCESS(rv, rv);
2098 
2099  nsCOMPtr<sbIMediaList> list = do_QueryInterface(library, &rv);
2100  NS_ENSURE_SUCCESS(rv, rv);
2101 
2102  rv = list->AddListener(this,
2103  PR_FALSE,
2109  nsnull);
2110  NS_ENSURE_SUCCESS(rv, rv);
2111  }
2112 
2113  mWatchingView = PR_TRUE;
2114 
2115  return NS_OK;
2116 }
2117 
2118 nsresult
2120 {
2121  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2122 
2123  nsAutoMonitor mon(mMonitor);
2124 
2125  // No view, we're probably playing single items
2126  if(!mView) {
2127  return NS_OK;
2128  }
2129 
2130  if(!mWatchingView) {
2131  return NS_OK;
2132  }
2133 
2134  nsresult rv = NS_ERROR_UNEXPECTED;
2135 
2136  if(mDelayedCheckTimer) {
2138  NS_ENSURE_SUCCESS(rv, rv);
2139 
2140  if(mDelayedCheckTimer) {
2141  rv = mDelayedCheckTimer->Cancel();
2142  NS_ENSURE_SUCCESS(rv, rv);
2143 
2144  mDelayedCheckTimer = nsnull;
2145  }
2146  }
2147 
2148  rv = mViewList->RemoveListener(this);
2149  NS_ENSURE_SUCCESS(rv, rv);
2150 
2151  rv = mView->RemoveListener(this);
2152  NS_ENSURE_SUCCESS(rv, rv);
2153 
2154  if(!mViewIsLibrary) {
2155  nsCOMPtr<sbIMediaItem> item = do_QueryInterface(mViewList, &rv);
2156  NS_ENSURE_SUCCESS(rv, rv);
2157 
2158  nsCOMPtr<sbILibrary> library;
2159  rv = item->GetLibrary(getter_AddRefs(library));
2160  NS_ENSURE_SUCCESS(rv, rv);
2161 
2162  nsCOMPtr<sbIMediaList> list = do_QueryInterface(library, &rv);
2163  NS_ENSURE_SUCCESS(rv, rv);
2164 
2165  rv = list->RemoveListener(this);
2166  NS_ENSURE_SUCCESS(rv, rv);
2167  }
2168 
2169  mWatchingView = PR_FALSE;
2170 
2171  mListBatchCount = 0;
2172  mLibraryBatchCount = 0;
2174 
2175  mViewIsLibrary = PR_FALSE;
2176  mNeedSearchPlayingItem = PR_FALSE;
2177  mNeedsRecalculate = PR_FALSE;
2178 
2179  return NS_OK;
2180 }
2181 
2182 nsresult
2184 {
2185  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2186 
2187  nsAutoMonitor mon(mMonitor);
2188 
2189  nsresult rv = NS_ERROR_UNEXPECTED;
2190  if(mDelayedCheckTimer) {
2191  rv = mDelayedCheckTimer->Cancel();
2192  NS_ENSURE_SUCCESS(rv, rv);
2193  }
2194  else {
2195  mDelayedCheckTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
2196  NS_ENSURE_SUCCESS(rv, rv);
2197  }
2198 
2199  rv = mDelayedCheckTimer->InitWithCallback(
2200  this, MEDIACORE_CHECK_DELAY, nsITimer::TYPE_ONE_SHOT);
2201  NS_ENSURE_SUCCESS(rv, rv);
2202 
2203  return NS_OK;
2204 }
2205 
2206 nsresult
2208 {
2209  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2210  NS_ENSURE_STATE(mView);
2211  NS_ENSURE_STATE(mCurrentItem);
2212 
2213  nsAutoMonitor mon(mMonitor);
2214 
2215  if(mNoRecalculate) {
2216  mNeedsRecalculate = PR_FALSE;
2217  return NS_OK;
2218  }
2219 
2220  nsString previousItemUID = mCurrentItemUID;
2221  PRUint32 previousItemIndex = mCurrentItemIndex;
2222 
2223  nsresult rv = NS_ERROR_UNEXPECTED;
2224 
2225  if(!mNeedSearchPlayingItem) {
2226  rv = mView->GetIndexForViewItemUID(mCurrentItemUID,
2228  }
2229  else {
2230  // Item not there anymore (by UID), just try and get
2231  // the item index by current item. We have to do this
2232  // for smart playlists.
2233  rv = mView->GetIndexForItem(mCurrentItem, &mCurrentItemIndex);
2234 
2235  if(NS_SUCCEEDED(rv)) {
2236  // Grab the new item uid.
2237  rv = mView->GetViewItemUIDForIndex(mCurrentItemIndex, mCurrentItemUID);
2238  NS_ENSURE_SUCCESS(rv, rv);
2239  }
2240  }
2241 
2242  // Ok, looks like we'll have to regenerate the sequence and start playing
2243  // from the new sequence only after the current item is done playing.
2244  mPositionInvalidated = NS_FAILED(rv) ? PR_TRUE: PR_FALSE;
2245 
2246  // If we should reset the position when the position is invalid,
2247  // do so now. Resetting the position is only necessary for filter,
2248  // search and xxx changes.
2250  mCurrentItemIndex = 0;
2251  }
2252 
2253  if(mCurrentItemIndex != previousItemIndex ||
2254  mCurrentItemUID != previousItemUID ||
2256 
2257  mNeedsRecalculate = PR_FALSE;
2258 
2259  PRInt64 currentItemIndex = sbIMediacoreSequencer::AUTO_PICK_INDEX;
2260  if (!mPositionInvalidated)
2261  currentItemIndex = mCurrentItemIndex;
2262  rv = RecalculateSequence(&currentItemIndex);
2263  NS_ENSURE_SUCCESS(rv, rv);
2264 
2265  if(!mPositionInvalidated) {
2266  nsCOMPtr<nsIVariant> variant = sbNewVariant(mCurrentItem).get();
2267  NS_ENSURE_TRUE(variant, NS_ERROR_OUT_OF_MEMORY);
2268 
2269  nsCOMPtr<sbIMediacoreEvent> event;
2271  nsnull,
2272  variant,
2273  mCore,
2274  getter_AddRefs(event));
2275  NS_ENSURE_SUCCESS(rv, rv);
2276 
2277  rv = DispatchMediacoreEvent(event);
2278  NS_ENSURE_SUCCESS(rv, rv);
2279  }
2280  }
2281 
2282  return NS_OK;
2283 }
2284 
2285 
2286 nsresult
2288  PRBool aAsync /*= PR_FALSE*/)
2289 {
2290  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2291  NS_ENSURE_ARG_POINTER(aEvent);
2292 
2293  nsresult rv = NS_ERROR_UNEXPECTED;
2294  nsCOMPtr<sbIMediacoreEventTarget> target =
2295  do_QueryReferent(mMediacoreManager, &rv);
2296  NS_ENSURE_SUCCESS(rv, rv);
2297 
2298  PRBool dispatched = PR_FALSE;
2299  rv = target->DispatchEvent(aEvent, aAsync, &dispatched);
2300  NS_ENSURE_SUCCESS(rv, rv);
2301 
2302  return NS_OK;
2303 }
2304 
2305 
2306 nsresult
2308 {
2309  nsresult rv;
2310 
2311  // Get the URI scheme for the media to playback
2312  nsCOMPtr<nsIURI> uri;
2313  rv = mPlaybackControl->GetUri(getter_AddRefs(uri));
2314  NS_ENSURE_SUCCESS(rv, rv);
2315  nsCAutoString scheme;
2316  rv = uri->GetScheme(scheme);
2317  NS_ENSURE_SUCCESS(rv, rv);
2318 
2319  // If attempting to play from an MTP device, dispatch an error event and do
2320  // nothing more
2321  if (scheme.Equals("x-mtp"))
2322  {
2323  // Create a mediacore error
2324  nsCOMPtr<sbMediacoreError> error;
2325  NS_NEWXPCOM(error, sbMediacoreError);
2326  NS_ENSURE_TRUE(error, NS_ERROR_OUT_OF_MEMORY);
2327 
2328  // Get the error message
2329  error->Init
2330  (0, sbStringBundle().Get("mediacore.device_media.error.text"));
2331 
2332  // Create the error event
2333  nsCOMPtr<sbIMediacoreEvent> event;
2335  error,
2336  nsnull,
2337  mCore,
2338  getter_AddRefs(event));
2339  NS_ENSURE_SUCCESS(rv, rv);
2340 
2341  // Dispatch the event
2342  nsCOMPtr<sbIMediacoreEventTarget> target = do_QueryInterface(mCore, &rv);
2343  NS_ENSURE_SUCCESS(rv, rv);
2344  PRBool dispatched;
2345  rv = target->DispatchEvent(event, PR_TRUE, &dispatched);
2346  NS_ENSURE_SUCCESS(rv, rv);
2347 
2348  return NS_OK;
2349  }
2350 
2351  // Start playback
2352  rv = mPlaybackControl->Play();
2353  NS_ENSURE_SUCCESS(rv, rv);
2354 
2355  return NS_OK;
2356 }
2357 
2358 nsresult
2360  nsIVariant* aData)
2361 {
2362  TRACE(("%s: item(%p)", __FUNCTION__, aItem));
2363  NS_ENSURE_ARG_POINTER(aItem);
2364 
2365  nsresult rv;
2366 
2367  PRBool hasVideo;
2368  rv = mDataRemoteFaceplatePlayingVideo->GetBoolValue(&hasVideo);
2369  if (NS_FAILED(rv) || !hasVideo) {
2370  // we only track last position for video
2371  return NS_OK;
2372  }
2373 
2374  PRUint64 position, duration;
2375 
2376  if (aData) {
2377  nsCOMPtr<nsISupports> supports;
2378  nsIID *iid = nsnull;
2379  rv = aData->GetAsInterface(&iid, getter_AddRefs(supports));
2380  NS_ENSURE_SUCCESS(rv, rv);
2381  nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(supports, &rv);
2382  NS_ENSURE_SUCCESS(rv, rv);
2383  rv = bag->GetPropertyAsUint64(NS_LITERAL_STRING("position"), &position);
2384  NS_ENSURE_SUCCESS(rv, rv);
2385  rv = bag->GetPropertyAsUint64(NS_LITERAL_STRING("duration"), &duration);
2386  NS_ENSURE_SUCCESS(rv, rv);
2387  nsCOMPtr<nsIURI> expectedURI;
2388  rv = bag->GetPropertyAsInterface(NS_LITERAL_STRING("uri"),
2389  NS_GET_IID(nsIURI),
2390  getter_AddRefs(expectedURI));
2391  NS_ENSURE_SUCCESS(rv, rv);
2392  nsCString expectedSpec;
2393  nsString actualSpec;
2394  rv = expectedURI->GetSpec(expectedSpec);
2395  NS_ENSURE_SUCCESS(rv, rv);
2396  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTURL), actualSpec);
2397  NS_ENSURE_SUCCESS(rv, rv);
2398  if (!expectedSpec.Equals(NS_ConvertUTF16toUTF8(actualSpec))) {
2399  // this isn't a stop, it's a track change; since we're way too late now,
2400  // don't set anything. We would have caught it from
2401  // sbMediacoreSequencer::Setup() anyway.
2402  return NS_OK;
2403  }
2404  }
2405  else {
2406  rv = mPlaybackControl->GetPosition(&position);
2407  NS_ENSURE_SUCCESS(rv, rv);
2408  rv = mPlaybackControl->GetDuration(&duration);
2409  NS_ENSURE_SUCCESS(rv, rv);
2410  }
2411 
2412  TRACE(("%s: position = %llu / %llu status %08x",
2413  __FUNCTION__, position, duration, mStatus));
2414 
2415  #ifdef PR_LOGGING
2416  do {
2417  nsString actualSpec;
2418  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CONTENTURL), actualSpec);
2419  if (NS_FAILED(rv)) break;
2420  TRACE(("%s[%p]: actual uri %s",
2421  __FUNCTION__, this,
2422  NS_ConvertUTF16toUTF8(actualSpec).get()));
2423  } while(0);
2424  #endif
2425 
2426  if (position == 0 || duration == 0) {
2427  // this is invalid, probably means things have already stopped
2428  return NS_OK;
2429  }
2430 
2431  /* the number of milliseconds before the end of the track where we will
2432  * consider this track have to finished playing (so the next play of this
2433  * track will not resume where we left off)
2434  */
2435  const PRUint64 TIME_BEFORE_END = 10 * PR_MSEC_PER_SEC;
2436  NS_NAMED_LITERAL_STRING(PROPERTY_LAST_POSITION, SB_PROPERTY_LASTPLAYPOSITION);
2437 
2438  if (position + TIME_BEFORE_END >= duration) {
2439  // this is near the end, just clear the remembered position
2440  rv = aItem->SetProperty(PROPERTY_LAST_POSITION, SBVoidString());
2441  NS_ENSURE_SUCCESS(rv, rv);
2442  }
2443  else {
2444  sbAutoString strPosition(position);
2445  rv = aItem->SetProperty(PROPERTY_LAST_POSITION, strPosition);
2446  NS_ENSURE_SUCCESS(rv, rv);
2447  }
2448 
2449  return NS_OK;
2450 }
2451 
2452 //------------------------------------------------------------------------------
2453 // sbIMediacoreSequencer
2454 //------------------------------------------------------------------------------
2455 
2456 NS_IMETHODIMP
2457 sbMediacoreSequencer::GetMode(PRUint32 *aMode)
2458 {
2459  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2460  NS_ENSURE_ARG_POINTER(aMode);
2461 
2462  nsAutoMonitor mon(mMonitor);
2463  *aMode = mMode;
2464 
2465  return NS_OK;
2466 }
2467 
2468 NS_IMETHODIMP
2469 sbMediacoreSequencer::SetMode(PRUint32 aMode)
2470 {
2471  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2472  nsresult rv;
2473 
2474  PRBool validMode = PR_FALSE;
2475  switch(aMode) {
2477  PRBool disableShuffle;
2478  rv = mDataRemotePlaylistShuffleDisabled->GetBoolValue(&disableShuffle);
2479  NS_ENSURE_SUCCESS(rv, rv);
2480  if (disableShuffle) {
2481  return NS_ERROR_FAILURE;
2482  }
2486  validMode = PR_TRUE;
2487  break;
2488  }
2489  NS_ENSURE_TRUE(validMode, NS_ERROR_INVALID_ARG);
2490 
2491  nsAutoMonitor mon(mMonitor);
2492 
2493  if(mMode != aMode) {
2494  mMode = aMode;
2495 
2496  PRInt64 viewPosition = mViewPosition;
2497  rv = RecalculateSequence(&viewPosition);
2498  NS_ENSURE_SUCCESS(rv, rv);
2499 
2500  rv = UpdateShuffleDataRemote(aMode);
2501  NS_ENSURE_SUCCESS(rv, rv);
2502  }
2503 
2504  return NS_OK;
2505 }
2506 
2507 NS_IMETHODIMP
2508 sbMediacoreSequencer::GetRepeatMode(PRUint32 *aRepeatMode)
2509 {
2510  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2511  NS_ENSURE_ARG_POINTER(aRepeatMode);
2512 
2513  nsAutoMonitor mon(mMonitor);
2514  *aRepeatMode = mRepeatMode;
2515 
2516  return NS_OK;
2517 }
2518 
2519 NS_IMETHODIMP
2520 sbMediacoreSequencer::SetRepeatMode(PRUint32 aRepeatMode)
2521 {
2522  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2523  nsresult rv;
2524 
2525  PRBool validMode = PR_FALSE;
2526  switch(aRepeatMode) {
2529  PRBool disableRepeat;
2530  rv = mDataRemotePlaylistRepeatDisabled->GetBoolValue(&disableRepeat);
2531  NS_ENSURE_SUCCESS(rv, rv);
2532  if (disableRepeat) {
2533  return NS_ERROR_FAILURE;
2534  }
2536  validMode = PR_TRUE;
2537  break;
2538  }
2539  NS_ENSURE_TRUE(validMode, NS_ERROR_INVALID_ARG);
2540 
2541  nsAutoMonitor mon(mMonitor);
2542  mRepeatMode = aRepeatMode;
2543 
2544  rv = UpdateRepeatDataRemote(aRepeatMode);
2545  NS_ENSURE_SUCCESS(rv, rv);
2546 
2547  return NS_OK;
2548 }
2549 
2550 NS_IMETHODIMP
2551 sbMediacoreSequencer::GetView(sbIMediaListView * *aView)
2552 {
2553  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2554  NS_ENSURE_ARG_POINTER(aView);
2555 
2556  nsAutoMonitor mon(mMonitor);
2557  NS_IF_ADDREF(*aView = mView);
2558 
2559  return NS_OK;
2560 }
2561 
2562 NS_IMETHODIMP
2563 sbMediacoreSequencer::SetView(sbIMediaListView * aView)
2564 {
2565  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2566  NS_ENSURE_ARG_POINTER(aView);
2567 
2568  return SetViewWithViewPosition(aView);
2569 }
2570 
2571 NS_IMETHODIMP
2572 sbMediacoreSequencer::GetViewPosition(PRUint32 *aViewPosition)
2573 {
2574  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2575  NS_ENSURE_ARG_POINTER(aViewPosition);
2576 
2577  nsAutoMonitor mon(mMonitor);
2578 
2579  // Position currently not valid, return with error.
2580  if(mPositionInvalidated) {
2581  return NS_ERROR_NOT_AVAILABLE;
2582  }
2583 
2584  *aViewPosition = mViewPosition;
2585 
2586  return NS_OK;
2587 }
2588 
2589 NS_IMETHODIMP
2590 sbMediacoreSequencer::GetCurrentItem(sbIMediaItem **aItem)
2591 {
2592  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2593  NS_ENSURE_ARG_POINTER(aItem);
2594 
2595  if (!NS_IsMainThread()) {
2596  // this method accesses the view, which isn't threadsafe.
2597  // proxy to the main thread to avoid hilarious crashes.
2598  nsresult rv;
2599  nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
2600  nsCOMPtr<sbIMediacoreSequencer> proxiedSeq;
2601  rv = do_GetProxyForObject(mainThread,
2602  NS_GET_IID(sbIMediacoreSequencer),
2603  NS_ISUPPORTS_CAST(sbIMediacoreSequencer*, this),
2604  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
2605  getter_AddRefs(proxiedSeq));
2606  NS_ENSURE_SUCCESS(rv, rv);
2607  rv = proxiedSeq->GetCurrentItem(aItem);
2608  NS_ENSURE_SUCCESS(rv, rv);
2609  return NS_OK;
2610  }
2611  // by default, if there's no current item, this doesn't throw, it returns a
2612  // null item instead.
2613  *aItem = nsnull;
2614 
2615  if(!mView) {
2616  return NS_OK;
2617  }
2618 
2619  PRUint32 index = 0;
2620  nsresult rv = mView->GetIndexForViewItemUID(mCurrentItemUID, &index);
2621  NS_ENSURE_SUCCESS(rv, NS_OK);
2622 
2623  rv = mView->GetItemByIndex(index, aItem);
2624  NS_ENSURE_SUCCESS(rv, NS_OK);
2625 
2626  return NS_OK;
2627 }
2628 
2629 NS_IMETHODIMP
2630 sbMediacoreSequencer::GetNextItem(sbIMediaItem **aItem)
2631 {
2632  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2633  NS_ENSURE_ARG_POINTER(aItem);
2634 
2635  nsAutoMonitor mon(mMonitor);
2636 
2638  NS_IF_ADDREF(*aItem = mCurrentItem);
2639  return NS_OK;
2640  }
2641 
2642  // by default, if there's no current item, this doesn't throw, it returns a
2643  // null item instead.
2644  *aItem = nsnull;
2645 
2646  PRUint32 nextPosition = mPositionInvalidated ? mPosition : mPosition + 1;
2647 
2648  if(!mView ||
2649  nextPosition >= mSequence.size()) {
2650  return NS_OK;
2651  }
2652 
2653  nsresult rv = mView->GetItemByIndex(mSequence[nextPosition], aItem);
2654  NS_ENSURE_SUCCESS(rv, rv);
2655 
2656  return NS_OK;
2657 }
2658 
2659 NS_IMETHODIMP
2660 sbMediacoreSequencer::GetCurrentSequence(nsIArray * *aCurrentSequence)
2661 {
2662  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2663  NS_ENSURE_ARG_POINTER(aCurrentSequence);
2664 
2665  nsresult rv = NS_ERROR_UNEXPECTED;
2666  nsCOMPtr<nsIMutableArray> array =
2667  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
2668  NS_ENSURE_SUCCESS(rv, rv);
2669 
2670  sequence_t::const_iterator it = mSequence.begin();
2671  for(; it != mSequence.end(); ++it) {
2672  nsCOMPtr<nsISupportsPRUint32> index =
2673  do_CreateInstance("@mozilla.org/supports-PRUint32;1", &rv);
2674  NS_ENSURE_SUCCESS(rv, rv);
2675 
2676  rv = index->SetData((*it));
2677  NS_ENSURE_SUCCESS(rv, rv);
2678 
2679  rv = array->AppendElement(index, PR_FALSE);
2680  NS_ENSURE_SUCCESS(rv, rv);
2681  }
2682 
2683  NS_ADDREF(*aCurrentSequence = array);
2684 
2685  return NS_OK;
2686 }
2687 
2688 NS_IMETHODIMP
2689 sbMediacoreSequencer::GetSequencePosition(PRUint32 *aSequencePosition)
2690 {
2691  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2692  NS_ENSURE_ARG_POINTER(aSequencePosition);
2693 
2694  nsAutoMonitor mon(mMonitor);
2695 
2696  // Position currently not valid, return with error.
2697  if(mPositionInvalidated) {
2698  return NS_ERROR_NOT_AVAILABLE;
2699  }
2700 
2701  *aSequencePosition = mPosition;
2702 
2703  return NS_OK;
2704 }
2705 
2706 NS_IMETHODIMP
2707 sbMediacoreSequencer::SetSequencePosition(PRUint32 aSequencePosition)
2708 {
2709  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2710  return NS_ERROR_NOT_IMPLEMENTED;
2711 }
2712 
2713 NS_IMETHODIMP
2714 sbMediacoreSequencer::PlayView(sbIMediaListView *aView,
2715  PRInt64 aItemIndex,
2716  PRBool aNotFromUserAction)
2717 {
2718  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2719  NS_ENSURE_ARG_POINTER(aView);
2720 
2721  nsresult rv = SetViewWithViewPosition(aView, &aItemIndex);
2722  NS_ENSURE_SUCCESS(rv, rv);
2723 
2724  PRBool proceed;
2725  rv = ValidateMediaItemControllerPlayback(!aNotFromUserAction,
2727  &proceed);
2728  NS_ENSURE_SUCCESS(rv, rv);
2729 
2730  if (!proceed) {
2731  return NS_OK;
2732  }
2733 
2734  rv = Play();
2735  NS_ENSURE_SUCCESS(rv, rv);
2736 
2737  if (!aNotFromUserAction) {
2738  // Fire EXPLICIT_TRACK_CHANGE when PlayView() is called.
2739  nsCOMPtr<sbIMediacoreEvent> event;
2741  nsnull,
2742  nsnull,
2743  mCore,
2744  getter_AddRefs(event));
2745  NS_ENSURE_SUCCESS(rv, rv);
2746 
2747  rv = DispatchMediacoreEvent(event);
2748  NS_ENSURE_SUCCESS(rv, rv);
2749  }
2750 
2751  return NS_OK;
2752 }
2753 
2754 NS_IMETHODIMP
2755 sbMediacoreSequencer::PlayURL(nsIURI *aURI)
2756 {
2757  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2758  NS_ENSURE_ARG_POINTER(aURI);
2759 
2760  nsAutoMonitor mon(mMonitor);
2761 
2763  mErrorCount = 0;
2764  mIsWaitingForPlayback = PR_TRUE;
2765 
2766  nsresult rv = ResetMetadataDataRemotes();
2767  NS_ENSURE_SUCCESS(rv, rv);
2768 
2769  // Reset the playing-video dataremote in case the user was previously
2770  // playing video
2772  NS_ENSURE_SUCCESS(rv, rv);
2773 
2774  // Setup() must be called without the monitor held, as must StartPlayback;
2775  // drop it so we do that.
2776  mon.Exit();
2777 
2778  rv = Setup(aURI);
2779  if(rv == NS_ERROR_ABORT) {
2780  NS_WARNING("Someone aborted playback of the next track.");
2781  return NS_OK;
2782  }
2783  NS_ENSURE_SUCCESS(rv, rv);
2784 
2786  NS_ENSURE_SUCCESS(rv, rv);
2787 
2788  rv = StartPlayback();
2789 
2790  if(NS_FAILED(rv)) {
2791  mon.Enter();
2792 
2794  mIsWaitingForPlayback = PR_FALSE;
2795 
2797  NS_ENSURE_SUCCESS(rv, rv);
2798 
2799  return rv;
2800  }
2801 
2802  return NS_OK;
2803 }
2804 
2805 NS_IMETHODIMP
2806 sbMediacoreSequencer::Play()
2807 {
2808  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2809 
2810  nsAutoMonitor mon(mMonitor);
2811 
2812  // No sequence, no error, but return right away.
2813  if(!mSequence.size()) {
2814  return NS_OK;
2815  }
2816 
2818  mErrorCount = 0;
2819  mIsWaitingForPlayback = PR_TRUE;
2820 
2821  // Always reset this data remote, otherwise the video window may get into
2822  // an unexpected state and not get shown ever again.
2823  nsresult rv = ResetPlayingVideoDataRemote();
2824  NS_ENSURE_SUCCESS(rv, rv);
2825 
2826  rv = ResetMetadataDataRemotes();
2827  NS_ENSURE_SUCCESS(rv, rv);
2828 
2829  // never call setup holding the monitor!
2830  mon.Exit();
2831 
2832  rv = Setup();
2833  if(rv == NS_ERROR_ABORT) {
2834  NS_WARNING("Someone aborted playback of the next track.");
2835  return NS_OK;
2836  }
2837  NS_ENSURE_SUCCESS(rv, rv);
2838 
2839  mon.Enter();
2840 
2842  NS_ENSURE_SUCCESS(rv, rv);
2843 
2844  mon.Exit();
2845 
2846  rv = StartPlayback();
2847 
2848  if(NS_FAILED(rv)) {
2849  mon.Enter();
2850 
2852  mIsWaitingForPlayback = PR_FALSE;
2853 
2855  NS_ENSURE_SUCCESS(rv, rv);
2856 
2857  return rv;
2858  }
2859 
2860  return NS_OK;
2861 }
2862 
2863 NS_IMETHODIMP
2864 sbMediacoreSequencer::Stop(PRBool aNotFromUserAction) {
2865  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2866 
2867  nsAutoMonitor mon(mMonitor);
2868 
2870 
2871  nsresult rv = StopSequenceProcessor();
2872  NS_ENSURE_SUCCESS(rv, rv);
2873 
2875  NS_ENSURE_SUCCESS(rv, rv);
2876 
2877  if(mPlaybackControl) {
2878  // Grip.
2879  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl = mPlaybackControl;
2880  mon.Exit();
2881 
2882  rv = playbackControl->Stop();
2883  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't stop core.");
2884 
2885  mon.Enter();
2886  }
2887 
2888  if(mSeenPlaying) {
2889  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_FALSE);
2890  NS_ENSURE_SUCCESS(rv, rv);
2891  }
2892 
2893  mSeenPlaying = PR_FALSE;
2894 
2895  nsCOMPtr<sbIMediacoreEvent> event;
2896  if (!aNotFromUserAction) {
2898  nsnull,
2899  nsnull,
2900  mCore,
2901  getter_AddRefs(event));
2902  NS_ENSURE_SUCCESS(rv, rv);
2903 
2904  rv = DispatchMediacoreEvent(event);
2905  NS_ENSURE_SUCCESS(rv, rv);
2906  }
2907 
2909  nsnull,
2910  nsnull,
2911  mCore,
2912  getter_AddRefs(event));
2913  NS_ENSURE_SUCCESS(rv, rv);
2914 
2915  rv = DispatchMediacoreEvent(event);
2916  NS_ENSURE_SUCCESS(rv, rv);
2917 
2918  return NS_OK;
2919 }
2920 
2921 NS_IMETHODIMP
2922 sbMediacoreSequencer::OnValidatePlaybackComplete(sbIMediaItem *aItem,
2923  PRInt32 aResult) {
2924  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2925 
2926  nsresult rv = NS_ERROR_UNEXPECTED;
2927 
2928  nsAutoMonitor mon(mMonitor);
2929 
2930  mValidationComplete = PR_TRUE;
2931 
2932  if (aItem == mValidatingItem) {
2933  switch (aResult) {
2935  if (mOnHoldStatus == ONHOLD_PLAYVIEW ||
2937 
2938  if (mOnHoldStatus == ONHOLD_PLAYVIEW) {
2939  rv = Play();
2940  NS_ENSURE_SUCCESS(rv, rv);
2941  }
2942 
2944  nsCOMPtr<sbIMediacoreEvent> event;
2945  rv = sbMediacoreEvent::
2947  nsnull,
2948  nsnull,
2949  mCore,
2950  getter_AddRefs(event));
2951  NS_ENSURE_SUCCESS(rv, rv);
2952 
2953  rv = DispatchMediacoreEvent(event);
2954  NS_ENSURE_SUCCESS(rv, rv);
2955  }
2956  }
2957 
2958  mon.Exit();
2959 
2960  if (mOnHoldStatus != ONHOLD_PLAYVIEW) {
2961  rv = ProcessNewPosition();
2962  NS_ENSURE_SUCCESS(rv, rv);
2963  }
2964  return NS_OK;
2966  // go to the next track in the view
2967  if (mOnHoldStatus == ONHOLD_PLAYVIEW) {
2969  mErrorCount = 0;
2970  mIsWaitingForPlayback = PR_TRUE;
2972  }
2974  return Previous(PR_TRUE);
2975  return Next(PR_TRUE);
2976  }
2977  }
2978  // else, a previous validation is done, but the user has triggered a new
2979  // playback event that cancelled the one that caused vaidation. Either a
2980  // new validation is in progress (in which case we'll get its completed
2981  // notification later with the correct mediaitem), or validation wasn't
2982  // needed anymore (in which case it is safe to ignore the event)
2983  return NS_OK;
2984 }
2985 
2986 nsresult
2988  PRInt32 aOnHoldStatus,
2989  PRBool *_proceed)
2990 {
2991  NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
2992  NS_ENSURE_ARG_POINTER(_proceed);
2993 
2994  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
2995  nsAutoMonitor mon(mMonitor);
2996 
2997  // No sequence, no error, but return right away.
2998  if(!mSequence.size()) {
2999  return NS_OK;
3000  }
3001 
3002  // get the item controller
3003  nsCOMPtr<sbIMediaItem> mediaItem;
3004  nsresult rv = mView->GetItemByIndex(mSequence[mPosition],
3005  getter_AddRefs(mediaItem));
3006  NS_ENSURE_SUCCESS(rv, rv);
3007 
3008  nsCOMPtr<sbIMediaItemController> mediaItemController;
3009  rv = mediaItem->GetItemController(getter_AddRefs(mediaItemController));
3010  NS_ENSURE_SUCCESS(rv, rv);
3011 
3012  if (mediaItemController) {
3013  // Call validatePlayback on the controller. Set _proceed to false so that
3014  // our caller doesn't do any more work. The validatePlayback call may
3015  // synchronously call completion callback and thus this won't always cause
3016  // playback to pause.
3017  mOnHoldStatus = aOnHoldStatus;
3018  mValidatingItem = mediaItem;
3019  mValidationFromUserAction = aFromUserAction;
3020  mValidationComplete = PR_FALSE;
3021  rv = mediaItemController->ValidatePlayback(mediaItem,
3022  aFromUserAction,
3023  this);
3024  *_proceed = PR_FALSE;
3025  return rv;
3026  }
3028  mValidatingItem.forget();
3029  *_proceed = PR_TRUE;
3030  return NS_OK;
3031 }
3032 
3033 NS_IMETHODIMP
3034 sbMediacoreSequencer::Next(PRBool aNotFromUserAction)
3035 {
3036  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3037 
3038  nsresult rv = NS_ERROR_UNEXPECTED;
3039 
3040  PRBool disableNext;
3041  rv = mDataRemotePlaylistNextDisabled->GetBoolValue(&disableNext);
3042  NS_ENSURE_SUCCESS(rv, rv);
3043  if (disableNext) {
3044  return NS_ERROR_FAILURE;
3045  }
3046 
3047  nsAutoMonitor mon(mMonitor);
3048 
3049  // No sequence, no error, return early.
3050  if(!mSequence.size()) {
3051  return NS_OK;
3052  }
3053 
3054  PRBool hasNext = PR_FALSE;
3055  PRUint32 length = mSequence.size();
3056 
3059  // Repeat the item only if the next action was the result of the stream
3060  // ending. Don't touch sequencer state. Don't even clear
3061  // mPositionInvalidated. Doing so can cause problems if the view changed.
3062  hasNext = PR_TRUE;
3063  }
3064  else if(mPositionInvalidated) {
3065  // The position of the currently playing item is invalid because we had to
3066  // regenerate a sequence that didn't include the currently playing item.
3067  // The next item should be at the current position instead of the current
3068  // position + 1.
3070  hasNext = PR_TRUE;
3071  mPositionInvalidated = PR_FALSE;
3072  }
3074  mPosition + 1 >= length) {
3075  mPosition = 0;
3077  hasNext = PR_TRUE;
3078 
3081  nsresult rv = RecalculateSequence();
3082  NS_ENSURE_SUCCESS(rv, rv);
3083  }
3084  }
3086  hasNext = PR_TRUE;
3087 
3088  // The next action was not the result of the stream ending, so act like
3089  // repeat all.
3090  if(mPosition + 1 >= length) {
3091  mPosition = 0;
3092  }
3093  else if(mPosition + 1 < length) {
3094  ++mPosition;
3095  }
3097  }
3098  else if(mPosition + 1 < length) {
3099  ++mPosition;
3101  hasNext = PR_TRUE;
3102  }
3103 
3104  // No next track, not an error.
3105  if(!hasNext) {
3106  // No next track and playing, stop.
3110  // Grip.
3111  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl = mPlaybackControl;
3112  mon.Exit();
3113  if (playbackControl) {
3114  rv = playbackControl->Stop();
3115  NS_ASSERTION(NS_SUCCEEDED(rv), "Stop failed at end of sequence.");
3116  }
3117  mon.Enter();
3118  }
3119 
3121 
3122  rv = StopSequenceProcessor();
3123  NS_ENSURE_SUCCESS(rv, rv);
3124 
3126  NS_ENSURE_SUCCESS(rv, rv);
3127 
3128  if(mSeenPlaying) {
3129  mSeenPlaying = PR_FALSE;
3130 
3131  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_FALSE);
3132  NS_ENSURE_SUCCESS(rv, rv);
3133  }
3134 
3135  nsCOMPtr<sbIMediacoreEvent> event;
3137  nsnull,
3138  nsnull,
3139  mCore,
3140  getter_AddRefs(event));
3141  NS_ENSURE_SUCCESS(rv, rv);
3142 
3143  rv = DispatchMediacoreEvent(event);
3144  NS_ENSURE_SUCCESS(rv, rv);
3145 
3146  return NS_OK;
3147  }
3148 
3149  PRBool proceed;
3150  rv = ValidateMediaItemControllerPlayback(!aNotFromUserAction, ONHOLD_NEXT, &proceed);
3151  NS_ENSURE_SUCCESS(rv, rv);
3152 
3153  if (!proceed) {
3154  return NS_OK;
3155  }
3156 
3157  // Fire EXPLICIT_TRACK_CHANGE when Next() was not triggered by the stream
3158  // ending.
3160  !aNotFromUserAction) {
3161  nsCOMPtr<sbIMediacoreEvent> event;
3162  rv = sbMediacoreEvent::
3164  nsnull,
3165  nsnull,
3166  mCore,
3167  getter_AddRefs(event));
3168  NS_ENSURE_SUCCESS(rv, rv);
3169 
3170  rv = DispatchMediacoreEvent(event);
3171  NS_ENSURE_SUCCESS(rv, rv);
3172  }
3173 
3174  mon.Exit();
3175 
3176  rv = ProcessNewPosition();
3177  NS_ENSURE_SUCCESS(rv, rv);
3178 
3179  return NS_OK;
3180 }
3181 
3182 NS_IMETHODIMP
3183 sbMediacoreSequencer::Previous(PRBool aNotFromUserAction)
3184 {
3185  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3186 
3187  nsresult rv = NS_ERROR_UNEXPECTED;
3188 
3189  PRBool disablePrevious;
3190  rv = mDataRemotePlaylistPreviousDisabled->GetBoolValue(&disablePrevious);
3191  NS_ENSURE_SUCCESS(rv, rv);
3192  if (disablePrevious) {
3193  return NS_ERROR_FAILURE;
3194  }
3195 
3196  nsAutoMonitor mon(mMonitor);
3197 
3198  // No sequence, no error, return early.
3199  if(!mSequence.size()) {
3200  return NS_OK;
3201  }
3202 
3203  PRBool hasNext = PR_FALSE;
3204  PRUint32 length = mSequence.size();
3205  PRInt64 position = mPosition;
3206 
3208  position - 1 < 0) {
3209  mPosition = length - 1;
3211  hasNext = PR_TRUE;
3212 
3215  nsresult rv = RecalculateSequence();
3216  NS_ENSURE_SUCCESS(rv, rv);
3217  }
3218  }
3220  hasNext = PR_TRUE;
3221 
3223  if(position - 1 < 0) {
3224  mPosition = length - 1;
3225  }
3226  else if(position - 1 >= 0) {
3227  --mPosition;
3228  }
3230  }
3231  }
3232  else if(position - 1 >= 0) {
3233  --mPosition;
3235  hasNext = PR_TRUE;
3236  }
3237 
3238  // No next track, not an error.
3239  if(!hasNext) {
3240  // No next track and playing, stop.
3244  // Grip.
3245  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl = mPlaybackControl;
3246  mon.Exit();
3247  rv = playbackControl->Stop();
3248  NS_ASSERTION(NS_SUCCEEDED(rv), "Stop failed at end of sequence.");
3249  mon.Enter();
3250  }
3251 
3253 
3254  rv = StopSequenceProcessor();
3255  NS_ENSURE_SUCCESS(rv, rv);
3256 
3258  NS_ENSURE_SUCCESS(rv, rv);
3259 
3260  if(mSeenPlaying) {
3261  mSeenPlaying = PR_FALSE;
3262 
3263  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_FALSE);
3264  NS_ENSURE_SUCCESS(rv, rv);
3265  }
3266 
3267  nsCOMPtr<sbIMediacoreEvent> event;
3269  nsnull,
3270  nsnull,
3271  mCore,
3272  getter_AddRefs(event));
3273  NS_ENSURE_SUCCESS(rv, rv);
3274 
3275  rv = DispatchMediacoreEvent(event);
3276  NS_ENSURE_SUCCESS(rv, rv);
3277 
3278  return NS_OK;
3279  }
3280 
3281  PRBool proceed;
3282  rv = ValidateMediaItemControllerPlayback(!aNotFromUserAction, ONHOLD_PREVIOUS, &proceed);
3283  NS_ENSURE_SUCCESS(rv, rv);
3284 
3285  if (!proceed) {
3286  return NS_OK;
3287  }
3288 
3289  // Fire EXPLICIT_TRACK_CHANGE when Previous() was not triggered by the stream
3290  // ending.
3292  !aNotFromUserAction) {
3293  nsCOMPtr<sbIMediacoreEvent> event;
3294  rv = sbMediacoreEvent::
3296  nsnull,
3297  nsnull,
3298  mCore,
3299  getter_AddRefs(event));
3300  NS_ENSURE_SUCCESS(rv, rv);
3301 
3302  rv = DispatchMediacoreEvent(event);
3303  NS_ENSURE_SUCCESS(rv, rv);
3304  }
3305 
3306  mon.Exit();
3307 
3308  rv = ProcessNewPosition();
3309  NS_ENSURE_SUCCESS(rv, rv);
3310 
3311  return NS_OK;
3312 }
3313 
3314 NS_IMETHODIMP
3315 sbMediacoreSequencer::RequestHandleNextItem(sbIMediacore *aMediacore)
3316 {
3317  // lone> Note that this method does not perform mediaitem trackType
3318  // service validation. This is only used for gapless playback (one
3319  // core to the same core), so the assumption here is that validated
3320  // playback on one track for a service gives access to all tracks
3321  // from that service. This is good enough for now but may not be anymore
3322  // at some point in the future. Fixing this will imply making cores
3323  // aware of the ability of the sequencer to set itself 'on hold'. When
3324  // this method (RequestHandleNextItem) is called, cores need to be able
3325  // to receive a "hold on, i don't know what track is going to be next yet"
3326  // answer, and call back into the sequencer later (after some event)
3327  // for the actual handling of the gapless next event. This means the
3328  // core could potentially run to the end of the stream before the
3329  // event has occured (slow login), and that could also have
3330  // implications.
3331  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3332  NS_ENSURE_ARG_POINTER(aMediacore);
3333 
3334  nsresult rv = NS_ERROR_UNEXPECTED;
3335 
3336  nsAutoMonitor mon(mMonitor);
3337  if(mIsWaitingForPlayback) {
3338  return NS_ERROR_NOT_AVAILABLE;
3339  }
3340  mon.Exit();
3341 
3342  nsCOMPtr<sbIMediaItem> item;
3343  rv = GetNextItem(getter_AddRefs(item));
3344  NS_ENSURE_SUCCESS(rv, rv);
3345 
3346  nsCOMPtr<nsIURI> uri;
3347  rv = item->GetContentSrc(getter_AddRefs(uri));
3348  NS_ENSURE_SUCCESS(rv, rv);
3349 
3350  mon.Enter();
3351  NS_ENSURE_TRUE(mCore == aMediacore, NS_ERROR_INVALID_ARG);
3352 
3353  nsCOMPtr<sbIMediacoreVoting> voting =
3354  do_QueryReferent(mMediacoreManager, &rv);
3355  NS_ENSURE_SUCCESS(rv, rv);
3356 
3357  NS_ENSURE_TRUE(voting, NS_ERROR_UNEXPECTED);
3358 
3359  mon.Exit();
3360 
3361  nsCOMPtr<sbIMediacoreVotingChain> votingChain;
3362  rv = voting->VoteWithURI(uri, getter_AddRefs(votingChain));
3363  NS_ENSURE_SUCCESS(rv, rv);
3364 
3365  PRBool validChain = PR_FALSE;
3366  rv = votingChain->GetValid(&validChain);
3367  NS_ENSURE_SUCCESS(rv, rv);
3368 
3369  NS_ENSURE_TRUE(validChain, NS_ERROR_UNEXPECTED);
3370 
3371  nsCOMPtr<nsIArray> chain;
3372  rv = votingChain->GetMediacoreChain(getter_AddRefs(chain));
3373  NS_ENSURE_SUCCESS(rv, rv);
3374 
3375  nsCOMPtr<sbIMediacore> core = do_QueryElementAt(chain, 0, &rv);
3376  NS_ENSURE_SUCCESS(rv, rv);
3377 
3378  mon.Enter();
3379 
3380  NS_ENSURE_TRUE(core == mCore, NS_ERROR_INVALID_ARG);
3381  mCoreWillHandleNext = PR_TRUE;
3382 
3383  return NS_OK;
3384 }
3385 
3386 NS_IMETHODIMP
3387 sbMediacoreSequencer::Abort()
3388 {
3389  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3390 
3391  nsAutoMonitor mon(mMonitor);
3392 
3393  // If we can't abort right now, just return NS_OK.
3394  NS_ENSURE_TRUE(mCanAbort, NS_OK);
3395 
3396  mShouldAbort = PR_TRUE;
3397 
3398  return NS_OK;
3399 }
3400 
3401 NS_IMETHODIMP
3402 sbMediacoreSequencer::GetCustomGenerator(
3403  sbIMediacoreSequenceGenerator * *aCustomGenerator)
3404 {
3405  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3406  NS_ENSURE_ARG_POINTER(aCustomGenerator);
3407 
3408  nsAutoMonitor mon(mMonitor);
3409  NS_IF_ADDREF(*aCustomGenerator = mCustomGenerator);
3410 
3411  return NS_OK;
3412 }
3413 
3414 NS_IMETHODIMP
3415 sbMediacoreSequencer::SetCustomGenerator(
3416  sbIMediacoreSequenceGenerator * aCustomGenerator)
3417 {
3418  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3419  NS_ENSURE_ARG_POINTER(aCustomGenerator);
3420 
3421  nsAutoMonitor mon(mMonitor);
3422  if(mCustomGenerator != aCustomGenerator) {
3423  mCustomGenerator = aCustomGenerator;
3424 
3425  // Custom generator changed and mode is custom, recalculate sequence
3427  PRInt64 viewPosition = mViewPosition;
3428  nsresult rv = RecalculateSequence(&viewPosition);
3429  NS_ENSURE_SUCCESS(rv, rv);
3430  }
3431  }
3432 
3433  return NS_OK;
3434 }
3435 
3436 //------------------------------------------------------------------------------
3437 // sbIMediacoreEventListener
3438 //------------------------------------------------------------------------------
3439 
3440 /* void onMediacoreEvent (in sbIMediacoreEvent aEvent); */
3441 NS_IMETHODIMP
3442 sbMediacoreSequencer::OnMediacoreEvent(sbIMediacoreEvent *aEvent)
3443 {
3444  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3445  NS_ENSURE_ARG_POINTER(aEvent);
3446 
3447  nsCOMPtr<sbIMediacore> core;
3448  nsresult rv = aEvent->GetOrigin(getter_AddRefs(core));
3449  NS_ENSURE_SUCCESS(rv, rv);
3450 
3451  PRUint32 eventType = 0;
3452  rv = aEvent->GetType(&eventType);
3453  NS_ENSURE_SUCCESS(rv, rv);
3454 
3455 #ifdef PR_LOGGING
3456  nsString coreName;
3457  rv = core->GetInstanceName(coreName);
3458  NS_ENSURE_SUCCESS(rv, rv);
3459 
3460  LOG(("[sbMediacoreSequencer] - Event from core '%s', type %08x",
3461  NS_ConvertUTF16toUTF8(coreName).BeginReading(), eventType));
3462 #endif
3463 
3464  nsAutoMonitor mon(mMonitor);
3465  if(mCore != core) {
3466  return NS_OK;
3467  }
3468 
3469  if(!(eventType == sbIMediacoreEvent::STREAM_STOP &&
3471  nsCOMPtr<sbIMediacoreEventTarget> target =
3472  do_QueryReferent(mMediacoreManager, &rv);
3473  NS_ENSURE_SUCCESS(rv, rv);
3474 
3475  PRBool dispatched;
3476  rv = target->DispatchEvent(aEvent, PR_TRUE, &dispatched);
3477  NS_ENSURE_SUCCESS(rv, rv);
3478  }
3479  mon.Exit();
3480 
3481  switch(eventType) {
3482 
3483  // Stream Events
3485  mon.Enter();
3486 
3489  mErrorCount = 0;
3490  mIsWaitingForPlayback = PR_FALSE;
3491  mStopTriggeredBySequencer = PR_FALSE;
3493 
3494  LOG(("[sbMediacoreSequencer] - Was waiting for playback, playback now started."));
3495  }
3496 
3499  }
3500 
3501  if(mCoreWillHandleNext) {
3503  nsresult rv = Next(PR_TRUE);
3504  NS_ENSURE_SUCCESS(rv, rv);
3505  }
3506 
3507  mon.Exit();
3508 
3510  NS_ENSURE_SUCCESS(rv, rv);
3511 
3512  rv = mDataRemoteFaceplateBuffering->SetBoolValue(PR_FALSE);
3513  NS_ENSURE_SUCCESS(rv, rv);
3514 
3515  if(!mSeenPlaying) {
3516  mSeenPlaying = PR_TRUE;
3517 
3518  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_TRUE);
3519  NS_ENSURE_SUCCESS(rv, rv);
3520  }
3521 
3522  // we may wish to restore the video position
3524  NS_ENSURE_STATE(mCurrentItem);
3525  NS_NAMED_LITERAL_STRING(PROPERTY_LAST_POSITION,
3527  nsString lastPositionStr;
3528  rv = mCurrentItem->GetProperty(PROPERTY_LAST_POSITION, lastPositionStr);
3529  NS_ENSURE_SUCCESS(rv, rv);
3530  rv = mCurrentItem->SetProperty(PROPERTY_LAST_POSITION, SBVoidString());
3531  NS_ENSURE_SUCCESS(rv, rv);
3532  PRUint64 lastPosition = nsString_ToUint64(lastPositionStr);
3533  if (lastPosition > 0) {
3534  TRACE(("%s[%p] - seeking to %llu (%s)",
3535  __FUNCTION__, this, lastPosition,
3536  NS_LossyConvertUTF16toASCII(lastPositionStr).get()));
3537  nsRefPtr<sbRunnableMethod1<sbMediacoreSequencer, nsresult, PRUint64> > runnable;
3539  ::New(getter_AddRefs(runnable),
3540  this,
3542  NS_ERROR_FAILURE,
3543  lastPosition);
3544  NS_ENSURE_SUCCESS(rv, rv);
3545  rv = NS_DispatchToCurrentThread(runnable);
3546  NS_ENSURE_SUCCESS(rv, rv);
3547  }
3548  }
3549 
3550  }
3551  break;
3552 
3554 
3555  mon.Enter();
3557  mStopTriggeredBySequencer = PR_FALSE;
3558  mon.Exit();
3559 
3561  NS_ENSURE_SUCCESS(rv, rv);
3562 
3563  rv = mDataRemoteFaceplateBuffering->SetBoolValue(PR_FALSE);
3564  NS_ENSURE_SUCCESS(rv, rv);
3565  }
3566  break;
3567 
3569  rv = mDataRemoteFaceplatePlayingVideo->SetBoolValue(PR_FALSE);
3570  NS_ENSURE_SUCCESS(rv, rv);
3571 
3572  mon.Enter();
3573  /* Track done, continue on to the next, if possible. */
3576 
3577  mCoreWillHandleNext = PR_FALSE;
3578 
3580  rv = Next(PR_TRUE);
3581 
3582  if(NS_FAILED(rv) ||
3583  mSequence.empty()) {
3584  mon.Exit();
3585  Stop(PR_TRUE);
3586  mon.Enter();
3587  }
3588 
3589  LOG(("[sbMediacoreSequencer] - Was playing, stream ended, attempting to go to next track in sequence."));
3590  }
3591  mon.Exit();
3592  }
3593  break;
3594 
3596  nsCOMPtr<nsIVariant> data;
3597  rv = aEvent->GetData(getter_AddRefs(data));
3598  NS_ENSURE_SUCCESS(rv, rv);
3599  NS_ENSURE_STATE(data);
3601  NS_ENSURE_SUCCESS(rv, rv);
3602  }
3603  break;
3604 
3606  mon.Enter();
3607 
3609  LOG(("[sbMediacoreSequencer] - Hard stop requested."));
3610  /* If we're explicitly stopped, don't continue to the next track,
3611  * just clean up... */
3613  mon.Exit();
3614 
3615  rv = StopSequenceProcessor();
3616  NS_ENSURE_SUCCESS(rv, rv);
3617 
3619  NS_ENSURE_SUCCESS(rv, rv);
3620 
3621  rv = ResetMetadataDataRemotes();
3622  NS_ENSURE_SUCCESS(rv, rv);
3623 
3624  rv = mDataRemoteFaceplatePlayingVideo->SetBoolValue(PR_FALSE);
3625  NS_ENSURE_SUCCESS(rv, rv);
3626 
3627  mon.Enter();
3628  if(mSeenPlaying) {
3629  mSeenPlaying = PR_FALSE;
3630  mon.Exit();
3631 
3632  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_FALSE);
3633  NS_ENSURE_SUCCESS(rv, rv);
3634 
3635  mon.Enter();
3636  }
3637  }
3638  else {
3639  mStopTriggeredBySequencer = PR_FALSE;
3640  }
3641  mon.Exit();
3642  }
3643  break;
3644 
3646  rv = mDataRemoteFaceplatePlayingVideo->SetBoolValue(PR_TRUE);
3647  NS_ENSURE_SUCCESS(rv, rv);
3648  }
3649  break;
3650 
3652  PRBool buffering = PR_FALSE;
3653 
3654  rv = mDataRemoteFaceplateBuffering->GetBoolValue(&buffering);
3655  NS_ENSURE_SUCCESS(rv, rv);
3656 
3657  if(!buffering) {
3658  rv = mDataRemoteFaceplateBuffering->SetBoolValue(PR_TRUE);
3659  NS_ENSURE_SUCCESS(rv, rv);
3660  }
3661 
3662  if(!mSeenPlaying) {
3663  mSeenPlaying = PR_TRUE;
3664 
3665  rv = mDataRemoteFaceplateSeenPlaying->SetBoolValue(PR_TRUE);
3666  NS_ENSURE_SUCCESS(rv, rv);
3667  }
3668  }
3669  break;
3670 
3671  // Error Events
3673  mon.Enter();
3674  mStopTriggeredBySequencer = PR_FALSE;
3675  mon.Exit();
3676 
3677  rv = HandleErrorEvent(aEvent);
3678  NS_ENSURE_SUCCESS(rv, rv);
3679  }
3680  break;
3681 
3682  // Misc events
3684  }
3685  break;
3686 
3688  rv = HandleMetadataEvent(aEvent);
3689  NS_ENSURE_SUCCESS(rv, rv);
3690  }
3691  break;
3692 
3694  rv = HandleMuteChangeEvent(aEvent);
3695  NS_ENSURE_SUCCESS(rv, rv);
3696  }
3697  break;
3698 
3700  rv = HandleVolumeChangeEvent(aEvent);
3701  NS_ENSURE_SUCCESS(rv, rv);
3702  }
3703  break;
3704 
3705  default:;
3706  }
3707 
3708  return NS_OK;
3709 }
3710 
3711 nsresult
3713 {
3714  TRACE(("%s[%p](%llu)", __FUNCTION__, this, aPosition));
3715  nsresult rv;
3716  #ifdef PR_LOGGING
3717  {
3718  nsString url;
3719  rv = mDataRemoteMetadataURL->GetStringValue(url);
3720  TRACE(("%s[%p] - url is %s", __FUNCTION__, this,
3721  NS_SUCCEEDED(rv) ? NS_LossyConvertUTF16toASCII(url).get()
3722  : "<none>"));
3723  }
3724  #endif
3725  NS_ENSURE_STATE(mPlaybackControl);
3726  rv = mPlaybackControl->SetPosition(aPosition);
3727  NS_ENSURE_SUCCESS(rv, rv);
3728  return NS_OK;
3729 }
3730 
3731 // -----------------------------------------------------------------------------
3732 // sbIMediacoreStatus
3733 // -----------------------------------------------------------------------------
3734 NS_IMETHODIMP
3735 sbMediacoreSequencer::GetState(PRUint32 *aState)
3736 {
3737  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3738 
3739  nsAutoMonitor mon(mMonitor);
3740  *aState = mStatus;
3741 
3742  return NS_OK;
3743 }
3744 
3745 // -----------------------------------------------------------------------------
3746 // sbIMediaListListener
3747 // -----------------------------------------------------------------------------
3748 NS_IMETHODIMP
3749 sbMediacoreSequencer::OnItemAdded(sbIMediaList *aMediaList,
3750  sbIMediaItem *aMediaItem,
3751  PRUint32 aIndex,
3752  PRBool *_retval)
3753 {
3754  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3755  NS_ENSURE_ARG_POINTER(aMediaList);
3756 
3757  nsAutoMonitor mon(mMonitor);
3758 
3759  // 2nd part of smart playlist rebuild detection: are we adding
3760  // items in the same batch as we cleared the list in ?
3761 
3762  if (aMediaList == mViewList && mListBatchCount) {
3764  // Our playing list is a smart playlist, and it is being rebuilt,
3765  // so make a note that we need to try to find the old playitem in
3766  // the new list (this will update the now playing icon in
3767  // tree views, and ensure that currentIndex returns the new index).
3768  // The 1st part of the detection has already scheduled a check, but
3769  // our search will occur before the check happens, so if the old
3770  // playing item no longer exists, playback will correctly stop.
3771  mNeedSearchPlayingItem = PR_TRUE;
3772  }
3773  else {
3774  mNeedsRecalculate = PR_TRUE;
3775  }
3776  }
3777  else {
3778  mNeedsRecalculate = PR_TRUE;
3779 
3780  nsresult rv = UpdateItemUIDIndex();
3781  NS_ENSURE_SUCCESS(rv, rv);
3782  }
3783 
3784  return NS_OK;
3785 }
3786 
3787 NS_IMETHODIMP
3788 sbMediacoreSequencer::OnBeforeItemRemoved(sbIMediaList *aMediaList,
3789  sbIMediaItem *aMediaItem,
3790  PRUint32 aIndex,
3791  PRBool *_retval)
3792 {
3793  *_retval = PR_TRUE;
3794  return NS_OK;
3795 }
3796 
3797 NS_IMETHODIMP
3798 sbMediacoreSequencer::OnAfterItemRemoved(sbIMediaList *aMediaList,
3799  sbIMediaItem *aMediaItem,
3800  PRUint32 aIndex,
3801  PRBool *_retval)
3802 {
3803  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3804  NS_ENSURE_ARG_POINTER(aMediaList);
3805 
3806  nsAutoMonitor mon(mMonitor);
3807 
3808  PRBool listEvent = (aMediaList == mViewList);
3809 
3810  nsresult rv = NS_ERROR_UNEXPECTED;
3811  nsCOMPtr<sbILibrary> library = do_QueryInterface(aMediaList, &rv);
3812 
3813  PRBool libraryEvent = PR_FALSE;
3814  if(!mViewIsLibrary && NS_SUCCEEDED(rv)) {
3815  libraryEvent = PR_TRUE;
3816  }
3817 
3818  // if this is an event on the library...
3819  if (libraryEvent) {
3820 
3821  // and the item is not our list, get more events if in a batch, or
3822  // just discard event if not in a batch.
3823  nsCOMPtr<sbIMediaItem> item = do_QueryInterface(mViewList, &rv);
3824  NS_ENSURE_SUCCESS(rv, rv);
3825 
3826  if (aMediaItem != item) {
3827  *_retval = PR_FALSE;
3828  return NS_OK;
3829  } else {
3830  if(mPlaybackControl) {
3831  // Grip.
3832  nsCOMPtr<sbIMediacorePlaybackControl> playbackControl = mPlaybackControl;
3833  mon.Exit();
3834 
3835  // if the item is our list, stop playback now and shutdown watcher
3836  rv = playbackControl->Stop();
3837  NS_ENSURE_SUCCESS(rv, rv);
3838 
3839  mon.Enter();
3840  }
3841 
3843 
3844  rv = StopSequenceProcessor();
3845  NS_ENSURE_SUCCESS(rv, rv);
3846 
3848  NS_ENSURE_SUCCESS(rv, rv);
3849 
3850  rv = StopWatchingView();
3851  NS_ENSURE_SUCCESS(rv, rv);
3852 
3853  // return value does not actually matter since shutdown removes our
3854  // listener
3855  *_retval = PR_FALSE;
3856  return NS_OK;
3857  }
3858  }
3859  // if this is a track being removed from our list, and we're in a batch,
3860  // don't get anymore events for this batch, we'll do the check when it
3861  // ends
3862  if (listEvent && mListBatchCount > 0) {
3863  // remember that we need to do a check when batch ends
3864  mNeedSearchPlayingItem = PR_TRUE;
3865  *_retval = PR_TRUE;
3866 
3867  return NS_OK;
3868  }
3869 
3870  // we have to delay the check for currentIndex, because its invalidation
3871  // relies on a medialistlistener (in the view) which may occur after
3872  // ours has been issued, in which case it will still be valid now.
3873  rv = DelayedCheck();
3874  NS_ENSURE_SUCCESS(rv, rv);
3875 
3876  *_retval = PR_FALSE;
3877 
3878  return NS_OK;
3879 }
3880 
3881 NS_IMETHODIMP
3882 sbMediacoreSequencer::OnItemUpdated(sbIMediaList *aMediaList,
3883  sbIMediaItem *aMediaItem,
3884  sbIPropertyArray *aProperties,
3885  PRBool *_retval)
3886 {
3887  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3888  NS_ENSURE_ARG_POINTER(aMediaList);
3889 
3890  nsAutoMonitor mon(mMonitor);
3891 
3892  nsCOMPtr<sbIMediaItem> item;
3893  nsresult rv = GetCurrentItem(getter_AddRefs(item));
3894  NS_ENSURE_SUCCESS(rv, rv);
3895 
3896  if(aMediaItem == item) {
3897  rv = SetMetadataDataRemotesFromItem(item, aProperties);
3898  NS_ENSURE_SUCCESS(rv, rv);
3899  }
3900 
3902  // Not only do we need to recalculate the sequence but we
3903  // also have to search for the playing item after a delay
3904  // to allow the metadata batch editor to settle down. UGH!
3905 
3906  // First check to see if the metadata actually has any effect on the view
3907  // If the modified metadata is not present in the view's cascade filter set
3908  // or sort array there is no need to recalculate the sequence
3909  if (!CheckPropertiesInfluenceView(aProperties)) {
3910  return NS_OK;
3911  }
3912 
3913  mNeedsRecalculate = PR_TRUE;
3914  mNeedSearchPlayingItem = PR_TRUE;
3915 
3916  // We must wait if there is a batch because rebuilding would
3917  // end up picking the wrong item.
3919  rv = DelayedCheck();
3920  NS_ENSURE_SUCCESS(rv, rv);
3921  }
3922 
3923  // Suppress this notification for the remainder of the batch
3924  *_retval = PR_TRUE;
3925  }
3926 
3927  return NS_OK;
3928 }
3929 
3930 NS_IMETHODIMP
3931 sbMediacoreSequencer::OnItemMoved(sbIMediaList *aMediaList,
3932  PRUint32 aFromIndex,
3933  PRUint32 aToIndex,
3934  PRBool *_retval)
3935 {
3936  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3937  NS_ENSURE_ARG_POINTER(aMediaList);
3938 
3939  nsAutoMonitor mon(mMonitor);
3940 
3941  if (aMediaList == mViewList && mListBatchCount) {
3943  mNeedSearchPlayingItem = PR_TRUE;
3944  }
3945  else {
3946  mNeedsRecalculate = PR_TRUE;
3947  }
3948  }
3949  else {
3950  mNeedsRecalculate = PR_TRUE;
3951 
3952  nsresult rv = UpdateItemUIDIndex();
3953  NS_ENSURE_SUCCESS(rv, rv);
3954  }
3955 
3956  return NS_OK;
3957 }
3958 
3959 NS_IMETHODIMP
3960 sbMediacoreSequencer::OnBeforeListCleared(sbIMediaList* aMediaList,
3961  PRBool aExcludeLists,
3962  PRBool* aNoMoreForBatch)
3963 {
3964  NS_ENSURE_ARG_POINTER(aMediaList);
3965  NS_ENSURE_ARG_POINTER(aNoMoreForBatch);
3966 
3967  // Don't care
3968  *aNoMoreForBatch = PR_TRUE;
3969  return NS_OK;
3970 }
3971 
3972 NS_IMETHODIMP
3973 sbMediacoreSequencer::OnListCleared(sbIMediaList *aMediaList,
3974  PRBool aExcludeLists,
3975  PRBool *_retval)
3976 {
3977  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
3978  NS_ENSURE_ARG_POINTER(aMediaList);
3979 
3980  nsAutoMonitor mon(mMonitor);
3981 
3982  // list or library cleared, playing item must have gone away, however
3983  // the item might be coming back immediately, in which case we want to
3984  // keep playing it, so delay the check.
3985  nsresult rv = DelayedCheck();
3986  NS_ENSURE_SUCCESS(rv, rv);
3987 
3988  // 1st part of smart playlist rebuild detection: is the event
3989  // occurring on our list and inside a batch ? if 2nd part never
3990  // happens, it could be a smart playlist rebuild that now has no
3991  // content, we don't care about that, the item will simply not be
3992  // found, and playback will correctly stop.
3993  if(mListBatchCount > 0 && aMediaList == mViewList) {
3995  }
3996 
3997  *_retval = PR_FALSE;
3998 
3999  return NS_OK;
4000 }
4001 
4002 NS_IMETHODIMP
4003 sbMediacoreSequencer::OnBatchBegin(sbIMediaList *aMediaList)
4004 {
4005  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4006  NS_ENSURE_ARG_POINTER(aMediaList);
4007 
4008  nsAutoMonitor mon(mMonitor);
4009 
4010  if(aMediaList == mViewList) {
4011  mListBatchCount++;
4012  }
4013  else {
4015  }
4016 
4017  return NS_OK;
4018 }
4019 
4020 NS_IMETHODIMP
4021 sbMediacoreSequencer::OnBatchEnd(sbIMediaList *aMediaList)
4022 {
4023  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4024  NS_ENSURE_ARG_POINTER(aMediaList);
4025 
4026  nsresult rv = NS_ERROR_UNEXPECTED;
4027  nsAutoMonitor mon(mMonitor);
4028 
4029  PRInt32 listBatchCount = mListBatchCount;
4030 
4031  if(aMediaList == mViewList && mListBatchCount > 0) {
4032  mListBatchCount--;
4033  }
4034  else if(mLibraryBatchCount > 0) {
4036  }
4037  else {
4038  mNeedsRecalculate = PR_TRUE;
4039  }
4040 
4041  if(mListBatchCount == 0 || mLibraryBatchCount == 0) {
4042 
4044  rv = DelayedCheck();
4045  NS_ENSURE_SUCCESS(rv, rv);
4046  }
4047  else if(mNeedsRecalculate) {
4048  rv = UpdateItemUIDIndex();
4049  NS_ENSURE_SUCCESS(rv, rv);
4050  }
4051  }
4052 
4053  if(mSmartRebuildDetectBatchCount == listBatchCount) {
4055  }
4056 
4057  return NS_OK;
4058 }
4059 
4060 PRBool
4062 {
4063  PRUint32 propertyCount = 0;
4064  nsresult rv = aProperties->GetLength(&propertyCount);
4065  NS_ENSURE_SUCCESS(rv, rv);
4066 
4067  if (!mPropertyManager) {
4069  do_GetService("@songbirdnest.com/Songbird/Properties/PropertyManager;1", &rv);
4070  NS_ENSURE_SUCCESS(rv, rv);
4071  }
4072 
4073  nsCOMPtr<sbICascadeFilterSet> cfs;
4074  PRUint16 filterCount = 0;
4075  nsCOMPtr<sbILibraryConstraint> constraint;
4076  PRUint32 constraintGroupCount = 0;
4077 
4078  nsCOMPtr<sbIFilterableMediaListView>
4079  filterableView = do_QueryInterface(mView);
4080  if (filterableView) {
4081  rv = filterableView->GetFilterConstraint(getter_AddRefs(constraint));
4082  NS_ENSURE_SUCCESS(rv, rv);
4083  if (constraint) {
4084  rv = constraint->GetGroupCount(&constraintGroupCount);
4085  NS_ENSURE_SUCCESS(rv, rv);
4086  }
4087  }
4088  else {
4089  rv = mView->GetCascadeFilterSet(getter_AddRefs(cfs));
4090  NS_ENSURE_SUCCESS(rv, rv);
4091  rv = cfs->GetLength(&filterCount);
4092  NS_ENSURE_SUCCESS(rv, rv);
4093  }
4094 
4095  nsCOMPtr<sbISortableMediaListView> sortableView;
4096  sortableView = do_QueryInterface(mView, &rv);
4097  NS_ENSURE_SUCCESS(rv, rv);
4098 
4099  nsCOMPtr<sbIPropertyArray> primarySortArray;
4100  rv = sortableView->GetCurrentSort(getter_AddRefs(primarySortArray));
4101  NS_ENSURE_SUCCESS(rv, rv);
4102 
4103  PRUint32 primarySortCount = 0;
4104  rv = primarySortArray->GetLength(&primarySortCount);
4105  NS_ENSURE_SUCCESS(rv, rv);
4106 
4107  nsCOMPtr<sbIProperty> property;
4108  for(PRUint32 propIndex = 0; propIndex < propertyCount; ++propIndex) {
4109  rv = aProperties->GetPropertyAt(propIndex, getter_AddRefs(property));
4110  NS_ENSURE_SUCCESS(rv, rv);
4111 
4112  nsString id;
4113  rv = property->GetId(id);
4114  NS_ENSURE_SUCCESS(rv, rv);
4115 
4116  // Check the filter constraint
4117  if (constraint) {
4118  for (PRUint32 groupIndex = 0;
4119  groupIndex < constraintGroupCount;
4120  ++groupIndex) {
4121  nsCOMPtr<sbILibraryConstraintGroup> group;
4122  rv = constraint->GetGroup(groupIndex, getter_AddRefs(group));
4123  NS_ENSURE_SUCCESS(rv, rv);
4124 
4125  PRBool hasProperty;
4126  rv = group->HasProperty(id, &hasProperty);
4127  NS_ENSURE_SUCCESS(rv, rv);
4128 
4129  if (hasProperty)
4130  return PR_TRUE;
4131  }
4132  }
4133 
4134  // Check the cascade filter set
4135  if (cfs) {
4136  for (PRUint16 filterIndex = 0; filterIndex < filterCount; ++filterIndex) {
4137  nsString filter;
4138  rv = cfs->GetProperty(filterIndex, filter);
4139  NS_ENSURE_SUCCESS(rv, rv);
4140 
4141  if (id.Equals(filter)) {
4142  // The property is present in the cascade filter set
4143  return PR_TRUE;
4144  }
4145  }
4146  }
4147 
4148  // Check the primary sort array
4149  nsCOMPtr<sbIProperty> sortProperty;
4150  for (PRUint32 sortIndex = 0; sortIndex < primarySortCount; ++sortIndex) {
4151  rv = primarySortArray->GetPropertyAt(sortIndex, getter_AddRefs(sortProperty));
4152  NS_ENSURE_SUCCESS(rv, rv);
4153 
4154  nsString SortId;
4155  rv = sortProperty->GetId(SortId);
4156  NS_ENSURE_SUCCESS(rv, rv);
4157 
4158  if (id.Equals(SortId)) {
4159  // The property is present in the primary sort
4160  return PR_TRUE;
4161  }
4162  }
4163 
4164  // Check secondary sorting
4165  nsCOMPtr<sbIPropertyInfo> propertyInfo;
4166  rv = mPropertyManager->GetPropertyInfo(id, getter_AddRefs(propertyInfo));
4167  NS_ENSURE_SUCCESS(rv, rv);
4168 
4169  nsCOMPtr<sbIPropertyArray> secondarySortArray;
4170  rv = propertyInfo->GetSecondarySort(getter_AddRefs(secondarySortArray));
4171  NS_ENSURE_SUCCESS(rv, rv);
4172 
4173  if (!secondarySortArray) {
4174  // This property doesn't have secondary sorting
4175  continue;
4176  }
4177 
4178  PRUint32 secondarySortCount = 0;
4179  rv = secondarySortArray->GetLength(&secondarySortCount);
4180  NS_ENSURE_SUCCESS(rv, rv);
4181 
4182  for (PRUint32 sortIndex = 0; sortIndex < secondarySortCount; ++sortIndex) {
4183  rv = secondarySortArray->GetPropertyAt(sortIndex, getter_AddRefs(sortProperty));
4184  NS_ENSURE_SUCCESS(rv, rv);
4185 
4186  nsString SortId;
4187  rv = sortProperty->GetId(SortId);
4188  NS_ENSURE_SUCCESS(rv, rv);
4189 
4190  if (id.Equals(SortId)) {
4191  // The property is present in the secondary sort
4192  return PR_TRUE;
4193  }
4194  }
4195  }
4196 
4197  // No properties were present in the cascade filter set, primary sort array or
4198  // secondary sort array
4199  return PR_FALSE;
4200 }
4201 
4202 
4203 // -----------------------------------------------------------------------------
4204 // sbIMediaListViewListener
4205 // -----------------------------------------------------------------------------
4206 NS_IMETHODIMP
4207 sbMediacoreSequencer::OnFilterChanged(sbIMediaListView *aChangedView)
4208 {
4209  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4210 
4211  nsAutoMonitor mon(mMonitor);
4212 
4214  mNeedsRecalculate = PR_TRUE;
4215 
4216  nsresult rv = UpdateItemUIDIndex();
4217  NS_ENSURE_SUCCESS(rv, rv);
4218 
4219  return NS_OK;
4220 }
4221 
4222 NS_IMETHODIMP
4223 sbMediacoreSequencer::OnSearchChanged(sbIMediaListView *aChangedView)
4224 {
4225  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4226 
4227  nsAutoMonitor mon(mMonitor);
4228 
4230  mNeedsRecalculate = PR_TRUE;
4231 
4232  nsresult rv = UpdateItemUIDIndex();
4233  NS_ENSURE_SUCCESS(rv, rv);
4234 
4235  return NS_OK;
4236 }
4237 
4238 NS_IMETHODIMP
4239 sbMediacoreSequencer::OnSortChanged(sbIMediaListView *aChangedView)
4240 {
4241  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4242 
4243  nsAutoMonitor mon(mMonitor);
4244 
4245  mNeedsRecalculate = PR_TRUE;
4246 
4247  nsresult rv = UpdateItemUIDIndex();
4248  NS_ENSURE_SUCCESS(rv, rv);
4249 
4250  return NS_OK;
4251 }
4252 
4253 
4254 // -----------------------------------------------------------------------------
4255 // nsITimerCallback
4256 // -----------------------------------------------------------------------------
4257 
4258 NS_IMETHODIMP
4259 sbMediacoreSequencer::Notify(nsITimer *timer)
4260 {
4261  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4262  NS_ENSURE_ARG_POINTER(timer);
4263 
4264  nsresult rv = NS_ERROR_UNEXPECTED;
4265  nsAutoMonitor mon(mMonitor);
4266 
4267  if(timer == mSequenceProcessorTimer) {
4268  rv = HandleSequencerTimer(timer);
4269  NS_ENSURE_SUCCESS(rv, rv);
4270  }
4271  else if(timer == mDelayedCheckTimer) {
4272  rv = HandleDelayedCheckTimer(timer);
4273  NS_ENSURE_SUCCESS(rv, rv);
4274  }
4275 
4276  return NS_OK;
4277 }
4278 
4279 nsresult
4281 {
4282  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4283  NS_ENSURE_ARG_POINTER(aTimer);
4284 
4285  nsresult rv = NS_ERROR_UNEXPECTED;
4286  PRUint64 position = 0;
4287 
4288  // Update the position in the position data remote.
4291  rv = mPlaybackControl->GetPosition(&position);
4292  if(NS_SUCCEEDED(rv)) {
4293  rv = UpdatePositionDataRemotes(position);
4294  NS_ENSURE_SUCCESS(rv, rv);
4295  }
4296  }
4297 
4301 
4302  PRUint64 duration = 0;
4303  rv = mPlaybackControl->GetDuration(&duration);
4304  if(NS_SUCCEEDED(rv)) {
4305  rv = UpdateDurationDataRemotes(duration);
4306  NS_ENSURE_SUCCESS(rv, rv);
4307 
4308  // only update the duration if we've played at least 5% of the
4309  // the track. This is to allow the duration to stabilize for
4310  // vbr files without proper headers.
4311  if((position > 0) && position > ((duration * 5) / 100)) {
4312  // only updates if there is a current item and the duration
4313  // reported by the core is different than the one the item
4314  // currently has.
4315  rv = UpdateCurrentItemDuration(duration);
4316  NS_ENSURE_SUCCESS(rv, rv);
4317  }
4318  }
4319  }
4320 
4321  return NS_OK;
4322 }
4323 
4324 nsresult
4326 {
4327  NS_ENSURE_TRUE(mMonitor, NS_ERROR_NOT_INITIALIZED);
4328  NS_ENSURE_STATE(mDelayedCheckTimer);
4329 
4330  nsAutoMonitor mon(mMonitor);
4331  mDelayedCheckTimer = nsnull;
4332 
4333  PRUint32 viewLength = 0;
4334  nsresult rv = mView->GetLength(&viewLength);
4335  NS_ENSURE_SUCCESS(rv, rv);
4336 
4337  if(mSequence.size() != viewLength) {
4338  mNeedsRecalculate = PR_TRUE;
4339  }
4340 
4341  rv = UpdateItemUIDIndex();
4342  NS_ENSURE_SUCCESS(rv, rv);
4343 
4344  mNeedSearchPlayingItem = PR_FALSE;
4345 
4346  return NS_OK;
4347 }
#define SB_MEDIACORE_DATAREMOTE_METADATA_REMAINING_STR
const unsigned long MODE_CUSTOM
Songbird Mediacore Error Definition.
nsCOMPtr< sbIMediacore > mCore
nsCOMPtr< sbIMediaItem > mCurrentItem
nsCOMPtr< sbIDataRemote > mDataRemotePlaylistRepeat
nsresult UpdateShuffleDataRemote(PRUint32 aMode)
nsresult UpdateMuteDataRemote(PRBool aMuted)
return NS_OK
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_VOLUME
#define SB_MEDIACORE_DATAREMOTE_METADATA_LENGTH_STR
Songbird Mediacore Event Definition.
#define MEDIACORE_UPDATE_NOTIFICATION_DELAY
nsresult HandleMetadataEvent(sbIMediacoreEvent *aEvent)
nsresult RecalculateSequence(PRInt64 *aViewPosition=nsnull)
const unsigned long STATUS_PLAYING
#define SB_MEDIACORE_DATAREMOTE_METADATA_ARTIST
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_MUTE
menuItem id
Definition: FeedWriter.js:971
onPageChanged aValue
Definition: FeedWriter.js:1395
const unsigned long MODE_REPEAT_ONE
attribute unsigned long repeatMode
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplateURL
const unsigned long SEQUENCE_END
Sequence end.
nsCOMPtr< nsITimer > mDelayedCheckTimer
inArray array
PRUint64 nsString_ToUint64(const nsAString &str, nsresult *rv)
#define SB_MEDIACORE_DATAREMOTE_METADATA_POSITION
nsIVariant * get() const
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataRemainingStr
const unsigned long STREAM_HAS_VIDEO
Stream has video.
#define LOG(args)
void SB_ConvertFloatVolToJSStringValue(PRFloat64 aVol, nsACString &aStrVol)
const unsigned long BEFORE_TRACK_CHANGE
Before the track playing is changed.
const NS_PREFSERVICE_CONTRACTID
#define SB_MEDIACORE_DATAREMOTE_METADATA_LENGTH
nsresult HandleVolumeChangeEvent(sbIMediacoreEvent *aEvent)
nsresult Setup(nsIURI *aURI=nsnull)
const unsigned long TRACK_CHANGE
Track playing has changed.
#define SB_MEDIACORE_DATAREMOTE_METADATA_TITLE
nsresult UpdateRepeatDataRemote(PRUint32 aRepeatMode)
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_SEENPLAYING
var event
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataPositionStr
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_PLAYING
nsresult DispatchMediacoreEvent(sbIMediacoreEvent *aEvent, PRBool aAsync=PR_FALSE)
const NS_ERROR_ABORT
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_BUFFERING
#define MEDIACORE_CHECK_DELAY
NS_IMPL_THREADSAFE_CI(sbMediaListEnumeratorWrapper)
const unsigned long STREAM_BEFORE_STOP
Stream is about to stop.
#define SB_MEDIACORE_DATAREMOTE_PLAYLIST_REPEAT_DISABLED
nsresult SetMetadataDataRemote(const nsAString &aId, const nsAString &aValue)
const unsigned long ERROR_EVENT
Indicates the event is an error and will have its error member set.
const unsigned long SEQUENCE_CHANGE
Sequence recalculated.
nsresult UpdateVolumeDataRemote(PRFloat64 aVolume)
PRPackedBool mNeedSearchPlayingItem
nsresult do_GetProxyForObject(nsIEventTarget *aTarget, REFNSIID aIID, nsISupports *aObj, PRInt32 aProxyType, void **aProxyObject)
#define SB_PROPERTY_LASTPLAYPOSITION
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplateMute
nsCOMPtr< sbIMediacorePlaybackControl > mPlaybackControl
const unsigned long METADATA_CHANGE
Metadata describing current item has changed.
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplateSeenPlaying
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataDuration
nsresult EmitMillisecondsToTimeString(PRUint64 aValue, nsAString &aString, PRBool aRemainingTime=PR_FALSE)
Songbird Variant Utility Definitions.
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplatePlaying
PRPackedBool mNextTriggeredByStreamEnd
nsCOMPtr< nsITimer > mSequenceProcessorTimer
A brief description of the contents of this interface.
const unsigned long EXPLICIT_STOP
Explicit call to stop the playback.
nsCOMPtr< sbIDataRemote > mDataRemotePlaylistNextDisabled
const unsigned long STREAM_STOP
Stream was stopped.
nsCOMPtr< sbIDataRemote > mDataRemotePlaylistPreviousDisabled
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataURL
NS_IMPL_THREADSAFE_RELEASE(sbRequestItem)
A distinct view on a given media list.
Interface to receive events from a mediaItemController.
Songbird Mediacore Event Definition.
const long VALIDATEPLAYBACKCOMPLETE_PROCEED
Result constant for onValidatePlaybackComplete used to proceed with playing the validated item...
const unsigned long MODE_FORWARD
The mode used to generate the sequence. Note that it is possible to disable shuffle mode using the pl...
NS_IMPL_THREADSAFE_ADDREF(sbRequestItem)
#define SB_MEDIACORE_DATAREMOTE_METADATA_GENRE
nsresult ValidateMediaItemControllerPlayback(PRBool aFromUserAction, PRInt32 aOnHoldStatus, PRBool *_proceed)
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplateBuffering
nsresult HandleSequencerTimer(nsITimer *aTimer)
NS_IMPL_QUERY_INTERFACE7_CI(sbMediacoreSequencer, sbIMediacoreSequencer, sbIMediacoreStatus, sbIMediaListListener, sbIMediaListViewListener, sbIMediaItemControllerListener, nsIClassInfo, nsITimerCallback) NS_IMPL_CI_INTERFACE_GETTER2(sbMediacoreSequencer
const unsigned long LISTENER_FLAGS_BATCHEND
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataTitle
Interface used to listen to changes to a media list.
PRPackedBool mResumePlaybackPosition
nsresult StopPlaybackHelper(nsAutoMonitor &aMonitor)
Definition of the sbIMediacoreEvent interface.
nsresult UpdateCurrentItemDuration(PRUint64 aDuration)
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplatePlayingVideo
const unsigned long BUFFERING
Buffering.
const unsigned long EXPLICIT_TRACK_CHANGE
Explicit call to next or previous.
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataArtist
_hideDatepicker duration
const unsigned long STREAM_START
Stream has started.
const unsigned long MODE_SHUFFLE
nsresult SeekCallback(PRUint64 aPosition)
nsresult HandleErrorEvent(sbIMediacoreEvent *aEvent)
const unsigned long STATUS_BUFFERING
#define SB_MEDIACORE_DATAREMOTE_METADATA_URL
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_PLAY_URL
#define SB_PROPERTY_GENRE
nsCOMPtr< sbIMediacoreSequenceGenerator > mCustomGenerator
nsCOMPtr< sbIMediacoreSequenceGenerator > mShuffleGenerator
nsCOMPtr< sbIDataRemote > mDataRemotePlaylistRepeatDisabled
const unsigned long LISTENER_FLAGS_BATCHBEGIN
const unsigned long TRACK_INDEX_CHANGE
Index in view of item currently playing has changed.
#define SB_MEDIACORE_DATAREMOTE_METADATA_POSITION_STR
PRPackedBool mIsWaitingForPlayback
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataDurationStr
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_PAUSED
const unsigned long VIEW_CHANGE
Sequencer view changed.
#define SB_MEDIACORE_DATAREMOTE_FACEPLATE_PLAYINGVIDEO
#define SB_MEDIACORE_DATAREMOTE_PLAYLIST_PREVIOUS_DISABLED
const unsigned long LISTENER_FLAGS_AFTERITEMREMOVED
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataPosition
#define SB_MEDIACORE_DATAREMOTE_METADATA_IMAGEURL
#define SB_PROPERTY_DURATION
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataImageURL
Songbird Thread Utilities Definitions.
std::vector< PRUint32 > sequence_t
nsresult SetMetadataDataRemotesFromItem(sbIMediaItem *aItem, sbIPropertyArray *aPropertiesChanged=nsnull)
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataAlbum
nsresult UpdateLastPositionProperty(sbIMediaItem *aItem, nsIVariant *aData)
nsCOMPtr< sbIMediaListView > mView
nsresult UpdateDurationDataRemotes(PRUint64 aDuration)
const unsigned long MODE_REVERSE
const unsigned long VOLUME_CHANGE
Volume has changed.
#define SB_PROPERTY_ARTISTNAME
Saved state of a media list view.
const unsigned long LISTENER_FLAGS_LISTCLEARED
#define SB_MEDIACORE_DATAREMOTE_PLAYLIST_SHUFFLE
static nsresult CreateEvent(PRUint32 aType, sbIMediacoreError *aError, nsIVariant *aData, sbIMediacore *aOrigin, sbIMediacoreEvent **retval)
nsCOMPtr< nsIArray > mChain
static nsresult New(SelfType **aRunnable, ClassType *aObject, MethodType aMethod, ReturnType aFailureReturnValue, Arg1Type aArg1Value)
#define TRACE(args)
Songbird String Bundle Definitions.
#define SB_MEDIACORE_DATAREMOTE_METADATA_ALBUM
const unsigned long LISTENER_FLAGS_ITEMMOVED
nsCOMPtr< sbIPropertyManager > mPropertyManager
const unsigned long STREAM_PAUSE
Stream is now paused.
sequencemap_t mViewIndexToSequenceIndex
PRBool CheckPropertiesInfluenceView(sbIPropertyArray *aProperties)
nsCOMPtr< sbIDataRemote > mDataRemotePlaylistShuffleDisabled
nsresult HandleDelayedCheckTimer(nsITimer *aTimer)
function url(spec)
var uri
Definition: FeedWriter.js:1135
const unsigned long STATUS_STOPPED
#define SB_MEDIACORE_DATAREMOTE_PLAYLIST_REPEAT
var prefs
Definition: FeedWriter.js:1169
countRef value
Definition: FeedWriter.js:1423
const unsigned long LISTENER_FLAGS_ITEMADDED
readonly attribute unsigned long viewPosition
The current position in the view. This position is tied to the sequencePosition.
const unsigned long BEFORE_VIEW_CHANGE
Sequencer view is about to change.
#define SB_PROPERTY_ALBUMNAME
nsresult GetItem(const sequence_t &aSequence, PRUint32 aPosition, sbIMediaItem **aItem)
const unsigned long MUTE_CHANGE
Mute status has changed.
sbIJobCancelable NS_DECL_CLASSINFO(sbGstreamerMediaInspector)
static void AppendInt(nsAString &str, PRInt64 val)
PRPackedBool mStopTriggeredBySequencer
function toggle(toShow, toHide, data, clickedActive, down)
const unsigned long MODE_REPEAT_ALL
nsCOMPtr< sbIMediaItem > mValidatingItem
nsCOMPtr< nsIWeakReference > mMediacoreManager
#define SB_MEDIACOREMANAGER_CONTRACTID
PRBool IsPropertyInPropertyArray(sbIPropertyArray *aPropArray, const nsAString &aPropName)
const unsigned long DURATION_CHANGE
Current duration has changed.
const long AUTO_PICK_INDEX
Allow the sequencer to pick the most appropriate start index for a sequence.
#define SB_MEDIACORE_DATAREMOTE_PLAYLIST_NEXT_DISABLED
const unsigned long STATUS_PAUSED
Interface that defines a single item of media in the system.
#define SB_PROPERTY_TRACKNAME
nsCOMPtr< sbIDataRemote > mDataRemotePlaylistShuffle
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplatePaused
nsCOMPtr< sbIDataRemote > mDataRemoteMetadataGenre
nsCOMPtr< sbIDataRemote > mDataRemoteFaceplateVolume
nsresult SetViewWithViewPosition(sbIMediaListView *aView, PRInt64 *aViewPosition=nsnull)
NS_IMPL_CI_INTERFACE_GETTER2(sbDataRemoteWrapper, sbIDataRemote, nsIClassInfo) sbDataRemoteWrapper
#define SB_MEDIACORE_DATAREMOTE_PLAYLIST_SHUFFLE_DISABLED
nsresult HandleMuteChangeEvent(sbIMediacoreEvent *aEvent)
const unsigned long LISTENER_FLAGS_ITEMUPDATED
#define MEDIACORE_MAX_SUBSEQUENT_ERRORS
restoreWindow aState
nsresult UpdateURLDataRemotes(nsIURI *aURI)
#define SB_PROPERTY_CONTENTURL
observe data
Definition: FeedWriter.js:1329
An interface to carry around arrays of nsIProperty instances. Users of this interface should only QI ...
const unsigned long STREAM_END
End of stream.
_getSelectedPageStyle s i
const unsigned long MODE_REPEAT_NONE
The repeat mode to use. Note that it is possible to disable repeat mode using the playlist...
#define SB_PROPERTY_PRIMARYIMAGEURL
Array filter(tab.attributes, function(aAttr){return(_this.xulAttributes.indexOf(aAttr.name) >-1);}).forEach(tab.removeAttribute
nsITimerCallback
nsresult UpdatePositionDataRemotes(PRUint64 aPosition)
var group
const long VALIDATEPLAYBACKCOMPLETE_SKIP
Result constant for onValidatePlaybackComplete used to skip item and continue on with the next in que...
nsCOMPtr< sbIMediaList > mViewList
_updateTextAndScrollDataForFrame aData