sbCDDeviceRequest.cpp
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2011 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
25 // Self imports.
26 #include "sbCDDevice.h"
27 #include "sbCDDeviceDefines.h"
28 
29 // Songbird imports.
30 #include <sbArray.h>
31 #include <sbDeviceTranscoding.h>
32 #include <sbDeviceUtils.h>
33 #include <sbFileUtils.h>
34 #include <sbIDeviceEvent.h>
35 #include <sbIAlbumArtScanner.h>
36 #include <sbIJobCancelable.h>
37 #include <sbIJobProgress.h>
38 #include <sbIMediacoreEventTarget.h>
39 #include <sbITranscodeAlbumArt.h>
40 #include <sbLibraryUtils.h>
41 #include <sbPrefBranch.h>
43 #include <sbStandardProperties.h>
44 #include <sbPropertiesCID.h>
45 #include <sbStringUtils.h>
46 #include <sbMemoryUtils.h>
48 #include <sbStatusPropertyValue.h>
49 #include <sbDeviceStatusHelper.h>
51 #include <sbVariantUtils.h>
52 #include <sbStandardProperties.h>
53 #include <sbWatchFolderUtils.h>
54 #include <sbDebugUtils.h>
55 
56 // Mozilla imports.
57 #include <nsCRT.h>
58 #include <nsArrayUtils.h>
59 #include <nsIBufferedStreams.h>
60 #include <nsIFile.h>
61 #include <nsIFileURL.h>
62 #include <nsIIOService.h>
63 #include <nsILocalFile.h>
64 #include <nsIProxyObjectManager.h>
65 #include <nsISimpleEnumerator.h>
66 #include <nsIStringEnumerator.h>
67 #include <nsIURI.h>
68 #include <nsIDOMWindow.h>
69 #include <nsIWindowWatcher.h>
70 #include <nsNetUtil.h>
71 #include <nsThreadUtils.h>
72 #include <nsComponentManagerUtils.h>
73 
74 #define SB_CD_DEVICE_AUTO_INVOKE(aName, aMethod) \
75  SB_AUTO_NULL_CLASS(aName, sbCDDevice*, mValue->aMethod)
76 
77 //
78 // Auto-disposal class wrappers.
79 //
80 // sbCDAutoFalse Wrapper to automatically set a boolean to false.
81 // sbCDAutoUnignoreItem Wrapper to auto ignore changes to a media
82 // item.
83 //
84 
85 SB_AUTO_NULL_CLASS(sbCDAutoFalse, PRBool*, *mValue = PR_FALSE);
86 SB_AUTO_CLASS2(sbCDAutoIgnoreItem,
87  sbCDDevice*,
88  sbIMediaItem*,
89  mValue != nsnull,
90  mValue->UnignoreMediaItem(mValue2),
91  mValue = nsnull);
92 
93 //
94 // Auto-sbCDAutoDeviceLocker unlocking class.
95 //
96 // sbCDAutoDeviceUnlock Wrapper class to automatically lock and unlock
97 // a device.
98 //
100 {
101 public:
103  : mCDDevice(aCDDevice)
104  {
105  // Only lock the device if it isn't already locked.
106  if (mCDDevice) {
107  nsresult rv;
108  PRBool isLocked = PR_FALSE;
109  rv = mCDDevice->GetIsDeviceLocked(&isLocked);
110  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
111  "Could not get the device lock state!");
112 
113  if (!isLocked) {
114  rv = mCDDevice->LockDevice();
115  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not lock the cd device!");
116  }
117  else {
118  // Set the device to |nsnull| here so we don't unlock a device that
119  // we didn't lock.
120  mCDDevice = nsnull;
121  }
122  }
123  }
124 
126  {
127  // Only unlock the device if it is already locked.
128  if (mCDDevice) {
129  nsresult rv;
130  PRBool isLocked = PR_FALSE;
131  rv = mCDDevice->GetIsDeviceLocked(&isLocked);
132  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
133  "Could not get the device lock state!");
134 
135  if (isLocked) {
136  rv = mCDDevice->UnlockDevice();
137  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not lock the cd device!");
138  }
139  }
140  }
141 
142 private:
143  nsCOMPtr<sbICDDevice> mCDDevice;
144 };
145 
146 //------------------------------------------------------------------------------
147 
148 void
149 sbCDDevice::InitRequestHandler()
150 {
151  SB_PRLOG_SETUP(sbCDDeviceRequest);
152 }
153 
154 nsresult
155 sbCDDevice::ProcessBatch(Batch & aBatch)
156 {
157  // Operate under the connect lock.
158  sbAutoReadLock autoConnectLock(mConnectLock);
159  NS_ENSURE_TRUE(mConnected, NS_ERROR_NOT_AVAILABLE);
160 
161  // Function variables.
162  nsresult rv;
163 
164  // Set up to automatically set the state to STATE_IDLE on exit. Any device
165  // operation must change the state to not be idle. This ensures that the
166  // device is not prematurely removed (e.g., ejected) while the device content
167  // is being accessed.
168  sbDeviceStatusAutoState autoState(mStatus, STATE_IDLE);
169 
170  // Snapshot the preferences to be used by the operations in this batch
171  sbPrefBranch prefBranch(PREF_CDDEVICE_RIPBRANCH, &rv);
172  NS_ENSURE_SUCCESS(rv, rv);
173  mPrefAutoEject = prefBranch.GetBoolPref(PREF_CDDEVICE_AUTOEJECT, PR_FALSE);
174  mPrefNotifySound = prefBranch.GetBoolPref(PREF_CDDEVICE_NOTIFYSOUND,
175  PR_FALSE);
176 
177  // Process each request in the batch
178  const Batch::const_iterator end = aBatch.end();
179  for (Batch::const_iterator iter = aBatch.begin();
180  iter != end;
181  ++iter) {
182  // Check for abort.
183  if (IsRequestAborted()) {
184 
185  PRBool isDeviceLocked = PR_FALSE;
186  rv = mCDDevice->GetIsDeviceLocked(&isDeviceLocked);
187  NS_ENSURE_SUCCESS(rv, rv);
188  if (isDeviceLocked) {
189  rv = mCDDevice->UnlockDevice();
190  NS_ENSURE_SUCCESS(rv, rv);
191  }
192 
193  // Don't keep a cached profile after an abort.
194  mTranscodeProfile = nsnull;
195  return NS_ERROR_ABORT;
196  }
197 
198  TransferRequest * requestItem = static_cast<TransferRequest*>(*iter);
199  const PRUint32 type = requestItem->GetType();
200 
201  rv = NS_OK;
202  // Dispatch processing of request.
203  LOG("sbCDDevice::ReqHandleRequestAdded 0x%08x\n", type);
204  switch (type)
205  {
207  mStatus->ChangeState(STATE_MOUNTING);
208  rv = ReqHandleMount(requestItem);
209  NS_ENSURE_SUCCESS(rv, rv);
210  break;
211 
213  mStatus->ChangeState(STATE_TRANSCODE);
214 
215  rv = ReqHandleRead(requestItem, aBatch.CountableItems());
216  if (rv != NS_ERROR_ABORT) {
217  // Warn of any errors
218  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
219  "Could not read a track off of disc!");
220  }
221  break;
222 
224  rv = Eject();
225  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not eject the CD!");
226  break;
227 
229  rv = AttemptCDLookup();
230  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not lookup CD data!");
231  break;
232 
234  rv = ReqHandleUpdate(requestItem);
235  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not update CD data!");
236  break;
237 
238  default :
239  NS_WARNING("Unsupported request type.");
240  break;
241  }
242  // null out the current request since it's completed
243  if (NS_SUCCEEDED(rv)) {
244  requestItem->SetIsProcessed(PR_TRUE);
245  }
246  }
247 
248  PRBool isAborted = (rv == NS_ERROR_ABORT);
249 
250  // If the device is currently locked, unlock it here.
251  // Always unlock before checking the result of the read request.
252  PRBool isDeviceLocked = PR_FALSE;
253  rv = mCDDevice->GetIsDeviceLocked(&isDeviceLocked);
254  NS_ENSURE_SUCCESS(rv, rv);
255  if (isDeviceLocked) {
256  rv = mCDDevice->UnlockDevice();
257  NS_ENSURE_SUCCESS(rv, rv);
258  }
259 
260  // If one of the above operatons returned |NS_ERROR_ABORT|, we need to
261  // bail out of this method.
262  if (isAborted) {
263  // Don't keep a cached profile after an abort.
264  mTranscodeProfile = nsnull;
265  return NS_ERROR_ABORT;
266  }
267 
268  return NS_OK;
269 }
270 
271 nsresult
272 sbCDDevice::ReqHandleMount(TransferRequest* aRequest)
273 {
274  // Validate arguments.
275  NS_ENSURE_ARG_POINTER(aRequest);
276 
277  // Function variables.
278  nsresult rv;
279 
280  // Log progress.
281  LOG("Enter sbCDDevice::ReqHandleMount \n");
282 
283  // Set up to auto-disconnect in case of error.
284  SB_CD_DEVICE_AUTO_INVOKE(AutoDisconnect, Disconnect()) autoDisconnect(this);
285 
286  TransferRequest * request = static_cast<TransferRequest*>(aRequest);
287 
288  // Update status and set for auto-failure.
290  mStatus,
291  sbDeviceStatusHelper::OPERATION_TYPE_MOUNT,
292  request,
293  0);
294 
295 
296  // Get the volume to mount.
297  nsRefPtr<sbBaseDeviceVolume> volume;
298  rv = GetVolumeForItem(request->list, getter_AddRefs(volume));
299  NS_ENSURE_SUCCESS(rv, rv);
300 
301  // Get the volume info.
302  nsRefPtr<sbDeviceStatistics> deviceStatistics;
303  rv = volume->GetStatistics(getter_AddRefs(deviceStatistics));
304  NS_ENSURE_SUCCESS(rv, rv);
305 
306  // Update the device library contents.
307  rv = UpdateDeviceLibrary(mDeviceLibrary);
308  NS_ENSURE_SUCCESS(rv, rv);
309 
310  // Add the library to the device statistics.
311  rv = deviceStatistics->AddLibrary(mDeviceLibrary);
312  NS_ENSURE_SUCCESS(rv, rv);
313 
314  // Update the device library CD disc hash.
315  nsAutoString cdDiscHash;
316  rv = GetCDDiscHash(mCDDevice, cdDiscHash);
317  NS_ENSURE_SUCCESS(rv, rv);
318  rv = mDeviceLibrary->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_CDDISCHASH),
319  cdDiscHash);
320  NS_ENSURE_SUCCESS(rv, rv);
321 
322  // Update status and clear auto-failure.
323  autoStatus.SetResult(NS_OK);
324 
325  // Cancel auto-disconnect.
326  autoDisconnect.forget();
327 
328  // Indicate that the Device is now ready.
329  CreateAndDispatchEvent(sbIDeviceEvent::EVENT_DEVICE_READY,
330  sbNewVariant(NS_ISUPPORTS_CAST(sbIDevice*, this)));
331 
332  LOG("Exit sbCDDevice::ReqHandleMount\n");
333  return NS_OK;
334 }
335 
336 
337 nsresult
338 sbCDDevice::UpdateDeviceLibrary(sbIDeviceLibrary* aLibrary)
339 {
340  // Validate arguments.
341  NS_ENSURE_ARG_POINTER(aLibrary);
342 
343  // Function variables.
344  nsresult rv;
345 
346  // Ignore library changes and set up to automatically stop ignoring.
347  SetIgnoreLibraryListener(PR_TRUE);
350  (AutoIgnoreLibraryListener,
351  SetIgnoreLibraryListener(PR_FALSE)) autoIgnoreLibraryListener(this);
353  (AutoIgnoreMediaListListeners,
354  SetIgnoreMediaListListeners(PR_FALSE)) autoIgnoreMediaListListeners(this);
355 
356  // Get the current CD disc hash.
357  nsAutoString cdDiscHash;
358  rv = GetCDDiscHash(mCDDevice, cdDiscHash);
359  NS_ENSURE_SUCCESS(rv, rv);
360 
361  // Get the previous CD disc hash.
362  nsAutoString prevCDDiscHash;
363  rv = aLibrary->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_CDDISCHASH),
364  prevCDDiscHash);
365  if (rv == NS_ERROR_NOT_AVAILABLE) {
366  prevCDDiscHash.Truncate();
367  rv = NS_OK;
368  }
369  NS_ENSURE_SUCCESS(rv, rv);
370 
371  // If the previous CD is being remounted, just set the friendly name and
372  // return.
373  if (cdDiscHash.Equals(prevCDDiscHash)) {
374  nsAutoString albumName;
375  rv = aLibrary->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME),
376  albumName);
377  if (NS_SUCCEEDED(rv) && !albumName.IsEmpty()) {
378  rv = mProperties->SetFriendlyName(albumName);
379  NS_ENSURE_SUCCESS(rv, rv);
380  }
381  else {
382  rv = mProperties->SetFriendlyName
383  (SBLocalizedString("cdrip.lookup.default_albumname"));
384  NS_ENSURE_SUCCESS(rv, rv);
385  }
386 
387  return NS_OK;
388  }
389 
390  // Mark the entire device library items as unavailable.
392  (aLibrary,
393  NS_LITERAL_STRING(SB_PROPERTY_AVAILABILITY),
394  NS_LITERAL_STRING("0"));
395  NS_ENSURE_SUCCESS(rv, rv);
396 
397  // Get the list of new media files.
398  nsCOMPtr<nsIArray> newFileURIList;
399  rv = GetMediaFiles(getter_AddRefs(newFileURIList));
400  NS_ENSURE_SUCCESS(rv, rv);
401 
402  // Get the list of new properties for each item.
403  nsCOMPtr<nsIArray> newPropsArray;
404  rv = GetMediaProperties(getter_AddRefs(newPropsArray));
405  NS_ENSURE_SUCCESS(rv, rv);
406 
407  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
408 
409  // Clear out any previous information.
410  rv = mDeviceLibrary->Clear();
411  NS_ENSURE_SUCCESS(rv, rv);
412 
413  // Update the library with the new media files.
414  nsCOMPtr<nsIArray> mediaItemList;
415  rv = mDeviceLibrary->BatchCreateMediaItems(newFileURIList,
416  newPropsArray,
417  PR_TRUE,
418  getter_AddRefs(mediaItemList));
419  NS_ENSURE_SUCCESS(rv, rv);
420 
421  // Get the number of created media items.
422  PRUint32 mediaItemCount;
423  rv = mediaItemList->GetLength(&mediaItemCount);
424  NS_ENSURE_SUCCESS(rv, rv);
425 
426  // Set a pref to indicate to the media view that it needs to perform a lookup
427  // once the view has been loaded.
428  sbPrefBranch prefBranch(PREF_CDDEVICE_RIPBRANCH, &rv);
429  NS_ENSURE_SUCCESS(rv, rv);
430  nsString deviceLibraryGuid;
431  rv = mDeviceLibrary->GetGuid(deviceLibraryGuid);
432  NS_ENSURE_SUCCESS(rv, rv);
433  deviceLibraryGuid.AppendLiteral(".needsLookup");
434  prefBranch.SetBoolPref(NS_ConvertUTF16toUTF8(deviceLibraryGuid).get(),
435  PR_TRUE);
436 
437  return NS_OK;
438 }
439 
440 nsresult
441 sbCDDevice::GetMediaFiles(nsIArray ** aURIList)
442 {
443  nsresult rv;
444 
445  nsCOMPtr<nsIMutableArray> list =
446  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1",
447  &rv);
448  NS_ENSURE_SUCCESS(rv, rv);
449 
450  nsCOMPtr<sbICDTOC> toc;
451  rv = mCDDevice->GetDiscTOC(getter_AddRefs(toc));
452  NS_ENSURE_SUCCESS(rv, rv);
453 
454  if (!toc) {
455  // If no TOC this would be really odd to occur, so we'll just return
456  return NS_OK;
457  }
458  nsCOMPtr<nsIArray> tracks;
459  rv = toc->GetTracks(getter_AddRefs(tracks));
460  NS_ENSURE_SUCCESS(rv, rv);
461 
462  nsCOMPtr<nsIIOService> ioservice =
463  do_ProxiedGetService("@mozilla.org/network/io-service;1", &rv);
464  NS_ENSURE_SUCCESS(rv, rv);
465 
466  nsCOMPtr<sbICDTOCEntry> entry;
467 
468  PRUint32 length;
469  rv = tracks->GetLength(&length);
470  NS_ENSURE_SUCCESS(rv, rv);
471 
472  for (PRUint32 index = 0; index < length; ++index) {
473  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
474  entry = do_QueryElementAt(tracks, index, &rv);
475  NS_ENSURE_SUCCESS(rv, rv);
476 
477  // Only append audio tracks to the library list.
478  PRInt16 curTrackMode;
479  rv = entry->GetTrackMode(&curTrackMode);
480  if (NS_FAILED(rv) || curTrackMode != sbICDTOCEntry::TRACKMODE_AUDIO) {
481  continue;
482  }
483 
484  if (NS_SUCCEEDED(rv)) {
485  nsString uriSpec;
486  rv = entry->GetTrackURI(uriSpec);
487  NS_ENSURE_SUCCESS(rv, rv);
488 
489  nsCOMPtr<nsIURI> uri;
490  rv = ioservice->NewURI(NS_LossyConvertUTF16toASCII(uriSpec),
491  nsnull,
492  nsnull,
493  getter_AddRefs(uri));
494  NS_ENSURE_SUCCESS(rv, rv);
495 
496  rv = list->AppendElement(uri, PR_FALSE);
497  NS_ENSURE_SUCCESS(rv, rv);
498  }
499  }
500 
501  rv = CallQueryInterface(list, aURIList);
502  NS_ENSURE_SUCCESS(rv, rv);
503 
504  return NS_OK;
505 }
506 
507 nsresult
508 sbCDDevice::GetMediaProperties(nsIArray ** aPropertyList)
509 {
510  nsresult rv;
511 
512  nsCOMPtr<nsIMutableArray> newPropsArray =
513  do_CreateInstance(SB_THREADSAFE_ARRAY_CONTRACTID, &rv);
514  NS_ENSURE_SUCCESS(rv, rv);
515 
516  nsCOMPtr<sbICDTOC> toc;
517  rv = mCDDevice->GetDiscTOC(getter_AddRefs(toc));
518  NS_ENSURE_SUCCESS(rv, rv);
519 
520  if (!toc) {
521  // If no TOC this would be really odd to occur, so we'll just return
522  return NS_OK;
523  }
524  nsCOMPtr<nsIArray> tracks;
525  rv = toc->GetTracks(getter_AddRefs(tracks));
526  NS_ENSURE_SUCCESS(rv, rv);
527 
528  nsCOMPtr<sbICDTOCEntry> entry;
529 
530  PRUint32 length;
531  rv = tracks->GetLength(&length);
532  NS_ENSURE_SUCCESS(rv, rv);
533 
534  for (PRUint32 index = 0; index < length; ++index) {
535  NS_ENSURE_FALSE(IsRequestAborted(), NS_ERROR_ABORT);
536  entry = do_QueryElementAt(tracks, index, &rv);
537  NS_ENSURE_SUCCESS(rv, rv);
538 
539  PRInt32 trackNumber;
540  rv = entry->GetTrackNumber(&trackNumber);
541  if (NS_SUCCEEDED(rv)) {
542  nsCOMPtr<sbIMutablePropertyArray> propList =
543  do_CreateInstance(SB_MUTABLEPROPERTYARRAY_CONTRACTID, &rv);
544  NS_ENSURE_SUCCESS(rv, rv);
545 
546  // By default mark all library items as "Should Rip".
547  rv = propList->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_SHOULDRIP),
548  NS_LITERAL_STRING("1"));
549  NS_ENSURE_SUCCESS(rv, rv);
550 
551  // number each track starting at 1
552  nsAutoString trackNumberStr;
553  trackNumberStr.AppendInt(trackNumber+1);
554  rv = propList->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNUMBER),
555  trackNumberStr);
556  NS_ENSURE_SUCCESS(rv, rv);
557 
558  // CDDA tracks always have 2 channels
559  rv = propList->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_CHANNELS),
560  NS_LITERAL_STRING("2"));
561  NS_ENSURE_SUCCESS(rv, rv);
562 
563  // and are always 44100 samples per second
564  rv = propList->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_SAMPLERATE),
565  NS_LITERAL_STRING("44100"));
566  NS_ENSURE_SUCCESS(rv, rv);
567 
568  // but have varying lengths (microseconds)
569  PRTime duration;
570  rv = entry->GetLength(&duration);
571  NS_ENSURE_SUCCESS(rv, rv);
572 
573  nsAutoString durationStr;
574  AppendInt(durationStr, duration);
575  rv = propList->AppendProperty(NS_LITERAL_STRING(SB_PROPERTY_DURATION),
576  durationStr);
577  NS_ENSURE_SUCCESS(rv, rv);
578 
579  newPropsArray->AppendElement(propList, false);
580  }
581  }
582 
583  rv = CallQueryInterface(newPropsArray, aPropertyList);
584  NS_ENSURE_SUCCESS(rv, rv);
585 
586  return NS_OK;
587 }
588 
589 void
590 sbCDDevice::ProxyCDLookup() {
591  nsresult rv;
592 
593  // Update the status
594  rv = mStatus->ChangeState(sbICDDeviceEvent::STATE_LOOKINGUPCD);
595  NS_ENSURE_SUCCESS(rv, /* void */);
596 
597  // Dispatch the event to notify listeners that we're about to start
598  // metadata lookup
600  sbNewVariant(NS_ISUPPORTS_CAST(sbIDevice*, this)));
601 
602  // Get the metadata manager and the default provider
603  nsCOMPtr<sbIMetadataLookupManager> mlm =
604  do_GetService("@songbirdnest.com/Songbird/MetadataLookup/manager;1", &rv);
605  NS_ENSURE_SUCCESS(rv, /* void */);
606 
607  nsCOMPtr<sbIMetadataLookupProvider> provider;
608  rv = mlm->GetDefaultProvider(getter_AddRefs(provider));
609 
610  // If there isn't a default provider, complete the CD lookup as if no results
611  // were available and return.
612  if (NS_FAILED(rv) || !provider) {
613  rv = CompleteCDLookup(nsnull);
614  NS_ENSURE_SUCCESS(rv, /* void */);
615  return;
616  }
617 
618  // Get our TOC
619  nsCOMPtr<sbICDTOC> toc;
620  rv = mCDDevice->GetDiscTOC(getter_AddRefs(toc));
621  NS_ENSURE_SUCCESS(rv, /* void */);
622 
623  // Initiate the metadata lookup
624  LOG("Querying metadata lookup provider for disc");
625  nsCOMPtr<sbIMetadataLookupJob> job;
626  rv = provider->QueryDisc(toc, getter_AddRefs(job));
627  if (NS_SUCCEEDED(rv) && job) {
628  // Check the state of the job, if the state reflects success already, then
629  // just invoke the progress listener directly, otherwise add the listener
630  // to the job.
631  PRUint16 jobStatus;
632  rv = job->GetStatus(&jobStatus);
633  NS_ENSURE_SUCCESS(rv, /* void */);
634  if (jobStatus == sbIJobProgress::STATUS_SUCCEEDED ||
635  jobStatus == sbIJobProgress::STATUS_FAILED)
636  {
637  rv = this->OnJobProgress(job);
638  NS_ENSURE_SUCCESS(rv, /* void */);
639  }
640  else {
641  rv = job->AddJobProgressListener((sbIJobProgressListener*)this);
642  NS_ENSURE_SUCCESS(rv, /* void */);
643  }
644  }
645  else {
646  // If the metadata lookup provider failed to provide a job, complete CD
647  // lookup as if no results were available.
648  rv = CompleteCDLookup(nsnull);
649  NS_ENSURE_SUCCESS(rv, /* void */);
650  }
651 }
652 
653 nsresult
654 sbCDDevice::ShowMetadataLookupDialog(const char *aLookupDialogURI,
655  nsISimpleEnumerator *aLookupResultsEnum,
656  PRBool aShouldReportEvents)
657 {
658  NS_ENSURE_ARG_POINTER(aLookupDialogURI);
659 
660  // Only append the results to the arg array if a valid ptr was passed in.
661  nsresult rv;
662  nsCOMPtr<nsIDOMWindow> parentWindow;
663  nsCOMPtr<nsIDOMWindow> domWindow;
664  nsCOMPtr<nsIWindowWatcher> windowWatcher =
665  do_ProxiedGetService("@mozilla.org/embedcomp/window-watcher;1", &rv);
666  NS_ENSURE_SUCCESS(rv, rv);
667  rv = windowWatcher->GetActiveWindow(getter_AddRefs(parentWindow));
668  NS_ENSURE_SUCCESS(rv, rv);
669 
670  // Prevent the device from being ejected while the metadata results dialog
671  // is getting shown. See bug 18354.
672  sbCDAutoDeviceLocker cdDeviceLocker(mCDDevice);
673 
674  // Build out the dialog arguments.
675  nsCOMPtr<nsIMutableArray> args =
676  do_CreateInstance("@songbirdnest.com/moz/xpcom/threadsafe-array;1", &rv);
677  NS_ENSURE_SUCCESS(rv, rv);
678 
679  // Always send over the device's library.
680  rv = args->AppendElement(mDeviceLibrary, PR_FALSE);
681  NS_ENSURE_SUCCESS(rv, rv);
682 
683  // Not all dialogs need metadata results dialogs.
684  if (aLookupResultsEnum) {
685  rv = args->AppendElement(aLookupResultsEnum, PR_FALSE);
686  NS_ENSURE_SUCCESS(rv, rv);
687  }
688 
689  // Throw up one of the metadata dialogs and prompt the user for
690  // the right artist/album info and populate each track with it.
691  rv = windowWatcher->OpenWindow(parentWindow,
692  aLookupDialogURI,
693  nsnull,
694  "centerscreen,chrome,modal,titlebar=no,resizable=no,scrollbars=yes",
695  args,
696  getter_AddRefs(domWindow));
697  NS_ENSURE_SUCCESS(rv, rv);
698 
699  if (aShouldReportEvents) {
700  // This method has been instructed to report events, do that now.
702  sbNewVariant(NS_ISUPPORTS_CAST(sbIDevice*, this)));
703  }
704 
705  return NS_OK;
706 }
707 
708 nsresult
709 sbCDDevice::AttemptCDLookup()
710 {
711  nsresult rv;
712 
713  if (!NS_IsMainThread()) {
714  nsCOMPtr<nsIThreadManager> threadMgr =
715  do_GetService("@mozilla.org/thread-manager;1", &rv);
716  NS_ENSURE_SUCCESS(rv, rv);
717 
718  nsCOMPtr<nsIThread> mainThread;
719  rv = threadMgr->GetMainThread(getter_AddRefs(mainThread));
720  NS_ENSURE_SUCCESS(rv, rv);
721 
722  nsCOMPtr<nsIRunnable> runnable =
723  NS_NEW_RUNNABLE_METHOD(sbCDDevice, this, ProxyCDLookup);
724  NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE);
725 
726  rv = mainThread->Dispatch(runnable, NS_DISPATCH_SYNC);
727  NS_ENSURE_SUCCESS(rv, rv);
728  }
729  else {
730  ProxyCDLookup();
731  }
732 
733  return NS_OK;
734 }
735 
736 nsresult
737 sbCDDevice::CompleteCDLookup(sbIJobProgress *aJob)
738 {
739  nsresult rv;
740 
741  rv = mStatus->ChangeState(STATE_IDLE);
742 
743  PRUint16 numResults = 0;
744  nsCOMPtr<nsISimpleEnumerator> metadataResultsEnum;
745  if (aJob) {
746  aJob->RemoveJobProgressListener(this);
747 
748  nsCOMPtr<sbIMetadataLookupJob> metalookupJob = do_QueryInterface(aJob, &rv);
749  NS_ENSURE_SUCCESS(rv, rv);
750 
751  rv = metalookupJob->GetMlNumResults(&numResults);
752  NS_ENSURE_SUCCESS(rv, rv);
753 
754  rv = metalookupJob->GetMetadataResults(getter_AddRefs(metadataResultsEnum));
755  NS_ENSURE_SUCCESS(rv, rv);
756 
757  // Dispatch the event to notify listeners that we've finished cdlookup
759  sbNewVariant(NS_ISUPPORTS_CAST(sbIDevice*, this)));
760  }
761 
762  LOG("Number of metadata lookup results found: %d", numResults);
763  // 3 cases to match up
764  if (numResults == 1) {
765  // Exactly 1 match found, automatically populate all the tracks with
766  // the metadata found in this result
767 
768  // There is only one returned item, so no need to loop through the
769  // enumerator here.
770  PRBool hasMore = PR_FALSE;
771  rv = metadataResultsEnum->HasMoreElements(&hasMore);
772  NS_ENSURE_SUCCESS(rv, rv);
773  NS_ENSURE_TRUE(hasMore, NS_ERROR_UNEXPECTED);
774 
775  nsCOMPtr<nsISupports> curItem;
776  rv = metadataResultsEnum->GetNext(getter_AddRefs(curItem));
777  NS_ENSURE_SUCCESS(rv, rv);
778 
779  nsCOMPtr<sbIMetadataAlbumDetail> albumDetail =
780  do_QueryInterface(curItem, &rv);
781  NS_ENSURE_SUCCESS(rv, rv);
782 
783  // Update the device library and friendly name with the new album name.
784  nsCOMPtr<sbIMutablePropertyArray> albumProperties;
785  rv = albumDetail->GetProperties(getter_AddRefs(albumProperties));
786  NS_ENSURE_SUCCESS(rv, rv);
787 
788  nsString albumName;
789  rv = albumProperties->GetPropertyValue(
790  NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME), albumName);
791  NS_ENSURE_SUCCESS(rv, rv);
792 
793  rv = mDeviceLibrary->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME),
794  albumName);
795  NS_ENSURE_SUCCESS(rv, rv);
796 
797  rv = mProperties->SetFriendlyName(albumName);
798  NS_ENSURE_SUCCESS(rv, rv);
799 
800  nsCOMPtr<nsIArray> trackPropResults;
801  rv = albumDetail->GetTracks(getter_AddRefs(trackPropResults));
802  NS_ENSURE_SUCCESS(rv, rv);
803 
804  PRUint32 length = 0;
805  rv = trackPropResults->GetLength(&length);
806  NS_ENSURE_SUCCESS(rv, rv);
807 
808  for (PRUint32 i = 0; i < length; i++) {
809  nsCOMPtr<sbIMutablePropertyArray> curTrackPropArray =
810  do_QueryElementAt(trackPropResults, i, &rv);
811  NS_ENSURE_SUCCESS(rv, rv);
812 
813  PRUint32 propCount = 0;
814  rv = curTrackPropArray->GetLength(&propCount);
815  if (NS_FAILED(rv) || propCount == 0) {
816  continue;
817  }
818 
819  // Get the media item in this device library that has the same track
820  // number (we add one due to the tracknumber being indexed from 1)
821  nsString indexStr;
822  indexStr.AppendInt(i+1);
823  nsCOMPtr<nsIArray> tracks;
824  rv = mDeviceLibrary->GetItemsByProperty(NS_LITERAL_STRING(
826  indexStr,
827  getter_AddRefs(tracks));
828  if(NS_FAILED(rv)) {
829  continue;
830  }
831 
832  // we should only ever have 1 matching track
833  PRUint32 length = 0;
834  rv = tracks->GetLength(&length);
835  NS_ENSURE_SUCCESS(rv, rv);
836  NS_ASSERTION(length == 1,
837  "More than one track in the device library with same #");
838 
839  // Append the new properties to the media item.
840  nsCOMPtr<sbIMediaItem> curLibraryItem = do_QueryElementAt(tracks, 0, &rv);
841  NS_ENSURE_SUCCESS(rv, rv);
842 
843  rv = curLibraryItem->SetProperties(curTrackPropArray);
844  NS_ENSURE_SUCCESS(rv, rv);
845  }
846  }
847  else {
848  rv = ShowMetadataLookupDialog(
849  (numResults == 0) ? NO_CD_INFO_FOUND_DIALOG_URI
851  metadataResultsEnum,
852  aJob ? PR_FALSE : PR_TRUE);
853  NS_ENSURE_SUCCESS(rv, rv);
854  }
855 
856  // If the device library album name is unknown, set the device friendly name
857  // to the default album name.
858  nsAutoString albumName;
859  PRBool albumNameUnknown = PR_FALSE;
860  rv = mDeviceLibrary->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME),
861  albumName);
862  if ((rv == NS_ERROR_NOT_AVAILABLE) || albumName.IsEmpty()) {
863  albumNameUnknown = PR_TRUE;
864  rv = mProperties->SetFriendlyName
865  (SBLocalizedString("cdrip.lookup.default_albumname"));
866  NS_ENSURE_SUCCESS(rv, rv);
867  }
868  else {
869  NS_ENSURE_SUCCESS(rv, rv);
870  }
871 
872  // If the album name is known, start an artwork scan.
873  if (!albumNameUnknown) {
874  nsCOMPtr<sbIAlbumArtScanner> artworkScanner =
875  do_CreateInstance("@songbirdnest.com/Songbird/album-art/scanner;1", &rv);
876  NS_ENSURE_SUCCESS(rv, rv);
877 
878  // Update any artwork already present.
879  rv = artworkScanner->SetUpdateArtwork(PR_TRUE);
880  NS_ENSURE_SUCCESS(rv, rv);
881 
882  rv = artworkScanner->ScanListForArtwork(mDeviceLibrary);
883  NS_ENSURE_SUCCESS(rv, rv);
884  }
885 
886  // Now that the metadata has been sorted out, post the metadata lookup
887  // complete event.
889  sbNewVariant(NS_ISUPPORTS_CAST(sbIDevice*, this)));
890 
891  return NS_OK;
892 }
893 
894 nsresult
895 sbCDDevice::ReqHandleUpdate(TransferRequest * aRequest)
896 {
897  nsresult rv;
898 
899  // See if the updated item is the device library.
900  nsCOMPtr<sbILibrary> library = do_QueryInterface(aRequest->item);
901 
902  // Set the device friendly name to the album name if the library was updated.
903  //XXXeps should only do this if the album name changed.
904  if (library) {
905  nsAutoString albumName;
906  rv = library->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ALBUMNAME),
907  albumName);
908  if (NS_SUCCEEDED(rv) && !albumName.IsEmpty()) {
909  rv = mProperties->SetFriendlyName(albumName);
910  NS_ENSURE_SUCCESS(rv, rv);
911  }
912  }
913 
914  return NS_OK;
915 }
916 
917 /*****
918  * sbIJobProgressListener
919  *****/
920 NS_IMETHODIMP
921 sbCDDevice::OnJobProgress(sbIJobProgress *aJob)
922 {
923  NS_ENSURE_ARG_POINTER(aJob);
924 
925  nsresult rv;
926  PRUint16 jobStatus;
927  rv = aJob->GetStatus(&jobStatus);
928  NS_ENSURE_SUCCESS(rv, rv);
929 
930  // Ignore still-running jobs
931  if (jobStatus == sbIJobProgress::STATUS_RUNNING)
932  return NS_OK;
933 
934  // Complete the CD lookup
935  rv = CompleteCDLookup(aJob);
936  NS_ENSURE_SUCCESS(rv, rv);
937 
938  return NS_OK;
939 }
940 
941 nsresult
942 sbCDDevice::GenerateFilename(sbIMediaItem *aItem,
943  nsACString & aOutFilename)
944 {
945  NS_ENSURE_ARG_POINTER(aItem);
946 
947  // The format for the filename should be "<track#> - <title>"
948  // I.e. "01 - DJFAIL MIX1"
949 
950  nsresult rv;
951  nsString trackNumProp;
952  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNUMBER),
953  trackNumProp);
954  NS_ENSURE_SUCCESS(rv, rv);
955 
956  // Pad at least one zero if we need to.
957  if (trackNumProp.Length() == 1) {
958  trackNumProp.Insert(NS_LITERAL_STRING("0"), 0);
959  }
960 
961  nsString trackNameProp;
962  rv = aItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_TRACKNAME),
963  trackNameProp);
964  NS_ENSURE_SUCCESS(rv, rv);
965 
966  aOutFilename.Append(NS_ConvertUTF16toUTF8(trackNumProp));
967  aOutFilename.AppendLiteral(" - ");
968  aOutFilename.Append(NS_ConvertUTF16toUTF8(trackNameProp));
969 
970  // Ensure we generate a valid filename by stripping illegal characters */
971  aOutFilename.StripChars(FILE_ILLEGAL_CHARACTERS);
972  // And path separators
973  aOutFilename.StripChars(FILE_PATH_SEPARATOR);
974  // And on win32, we cannot start or end with a space or dot.
975  // Do this everywhere (rather than just win32) for consistency
976  aOutFilename.Trim(" .", PR_TRUE, PR_TRUE);
977 
978  // Now give it a 'dummy' file extension. We'll replace this with the correct
979  // extension for the format we transcode to, but we don't want to mistake
980  // something else in the filename for the file extension.
981  aOutFilename.AppendLiteral(".cdda");
982 
983  return NS_OK;
984 }
985 
986 nsresult
987 sbCDDevice::ReqHandleRead(TransferRequest * aRequest, PRUint32 aBatchCount)
988 {
989  NS_ENSURE_ARG_POINTER(aRequest);
990 
991  LOG("Enter sbMSCDeviceBase::ReqHandleRead\n");
992 
993  nsresult rv;
994 
996  (mStatus,
998  aRequest,
999  aBatchCount);
1000 
1001  // Ensure that the device is locked during a read operation.
1002  sbCDAutoDeviceLocker autoDeviceLocker(mCDDevice);
1003 
1004  nsCOMPtr<sbIMediaItem> source = do_QueryInterface(aRequest->data, &rv);
1005  NS_ENSURE_SUCCESS(rv, rv);
1006 
1009  rv = source->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_CDRIP_STATUS),
1010  value.GetValue());
1011  NS_ENSURE_SUCCESS(rv, rv);
1012 
1013  sbIMediaItem * destination = aRequest->item;
1014 
1015  // We're creating a copy of the file so we want to break the link back to
1016  // the CD device library item, especially since it's semi-transient
1017  SBVoidString voidString;
1018  destination->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_ORIGINITEMGUID),
1019  voidString);
1020  destination->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_ORIGINLIBRARYGUID),
1021  voidString);
1022 
1023  // Find the preferred audio transcoding profile.
1024  if (!mTranscodeProfile)
1025  {
1028  getter_AddRefs(mTranscodeProfile));
1029  NS_ENSURE_SUCCESS(rv, rv);
1030 
1031  // Cache the bitrate (as a string) so that it can be applied to
1032  // the tracks as they're created. This avoids the problem where
1033  // tracks are marked with the wrong bitrate if the user changes
1034  // his transcoding prefs after inserting a cd.
1035  mTranscodeBitrateStr.Truncate();
1036  nsCOMPtr<nsIVariant> bitrateVariant;
1038  NS_LITERAL_STRING("bitrate"),
1039  getter_AddRefs(bitrateVariant));
1040  if (NS_SUCCEEDED(rv) && bitrateVariant) {
1041  PRUint32 bitrate;
1042  rv = bitrateVariant->GetAsUint32(&bitrate);
1043  if (NS_SUCCEEDED(rv))
1044  mTranscodeBitrateStr.AppendInt(bitrate/1000);
1045  }
1046  }
1047 
1048  if (!mTranscodeBitrateStr.IsEmpty()) {
1049  destination->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_BITRATE),
1050  mTranscodeBitrateStr);
1051  }
1052 
1053  nsCOMPtr<nsIURI> sourceContentURI;
1054  rv = source->GetContentSrc(getter_AddRefs(sourceContentURI));
1055  NS_ENSURE_SUCCESS(rv, rv);
1056 
1057  // Retrieve the managed path if the media management service is enabled.
1058  nsCOMPtr<nsIURI> musicFolderURI;
1059  rv = RegenerateMediaURL(destination, getter_AddRefs(musicFolderURI));
1060  NS_ENSURE_SUCCESS(rv, rv);
1061 
1062  nsCOMPtr<nsIURL> musicFolderURL = do_QueryInterface(musicFolderURI, &rv);
1063  NS_ENSURE_SUCCESS(rv, rv);
1064 
1065  nsCString extension;
1066  rv = sbDeviceUtils::GetTranscodedFileExtension(mTranscodeProfile, extension);
1067  NS_ENSURE_SUCCESS(rv, rv);
1068 
1069  musicFolderURL->SetFileExtension(extension);
1070 
1071  // Create a unique media file and set it up for auto removal on error.
1072  nsCOMPtr<nsIFile> mediaFile;
1073  rv = CreateUniqueMediaFile(musicFolderURL,
1074  getter_AddRefs(mediaFile),
1075  getter_AddRefs(musicFolderURI));
1076  NS_ENSURE_SUCCESS(rv, rv);
1077  sbAutoRemoveFile autoRemoveMediaFile(mediaFile);
1078 
1079  // Ignore item update block
1080  {
1081  // Prevent notification while we set the content source on the item
1082  sbCDAutoIgnoreItem autoUnignore(this, destination);
1083 
1084  // Update the content URI to point to where the item will be organized.
1085  nsCOMPtr<nsIURI> contentURI;
1086  rv = sbLibraryUtils::GetContentURI(musicFolderURI,
1087  getter_AddRefs(contentURI));
1088  rv = destination->SetContentSrc(contentURI);
1089  NS_ENSURE_SUCCESS(rv, rv);
1090  }
1091 
1092  nsCOMPtr<sbITranscodeJob> tcJob = do_CreateInstance(
1093  "@songbirdnest.com/Songbird/Mediacore/Transcode/GStreamer;1", &rv);
1094  NS_ENSURE_SUCCESS(rv, rv);
1095 
1096  nsCOMPtr<nsIThread> target;
1097  rv = NS_GetMainThread(getter_AddRefs(target));
1098  NS_ENSURE_SUCCESS(rv, rv);
1099 
1100  nsCOMPtr<sbITranscodeJob> proxiedJob;
1101  rv = do_GetProxyForObject(target,
1102  tcJob.get(),
1103  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
1104  getter_AddRefs(proxiedJob));
1105  NS_ENSURE_SUCCESS(rv, rv);
1106 
1107  rv = proxiedJob->SetProfile(mTranscodeProfile);
1108  NS_ENSURE_SUCCESS(rv, rv);
1109 
1110  nsCString URISpec;
1111  rv = musicFolderURI->GetSpec(URISpec);
1112  NS_ENSURE_SUCCESS(rv, rv);
1113 
1114  // Setup the ignore rule w/ the watch folder service.
1115  nsRefPtr<sbAutoIgnoreWatchFolderPath> autoWFPathIgnore =
1117  NS_ENSURE_TRUE(autoWFPathIgnore, NS_ERROR_OUT_OF_MEMORY);
1118 
1119  nsCOMPtr<nsIFileURL> destFileURL =
1120  do_QueryInterface(musicFolderURI, &rv);
1121  NS_ENSURE_SUCCESS(rv, rv);
1122 
1123  nsCOMPtr<nsIFile> destFileSpec;
1124  rv = destFileURL->GetFile(getter_AddRefs(destFileSpec));
1125  NS_ENSURE_SUCCESS(rv, rv);
1126 
1127  nsString destFilePath;
1128  rv = destFileSpec->GetPath(destFilePath);
1129  NS_ENSURE_SUCCESS(rv, rv);
1130 
1131  rv = autoWFPathIgnore->Init(destFilePath);
1132  NS_ENSURE_SUCCESS(rv, rv);
1133 
1134  rv = proxiedJob->SetDestURI(NS_ConvertUTF8toUTF16(URISpec));
1135  NS_ENSURE_SUCCESS(rv, rv);
1136 
1137  rv = sourceContentURI->GetSpec(URISpec);
1138  NS_ENSURE_SUCCESS(rv, rv);
1139 
1140  rv = proxiedJob->SetSourceURI(NS_ConvertUTF8toUTF16(URISpec));
1141  NS_ENSURE_SUCCESS(rv, rv);
1142 
1143  // Set the metadata for the job
1144  nsCOMPtr<sbIPropertyArray> metadata;
1145  rv = aRequest->item->GetProperties(nsnull, getter_AddRefs(metadata));
1146  NS_ENSURE_SUCCESS(rv, rv);
1147 
1148  rv = proxiedJob->SetMetadata(metadata);
1149  NS_ENSURE_SUCCESS(rv, rv);
1150 
1151  nsCOMPtr<sbITranscodeAlbumArt> albumArt = do_CreateInstance(
1153  NS_ENSURE_SUCCESS(rv, rv);
1154 
1155  nsCOMPtr<nsIArray> imageFormats = do_CreateInstance(
1157  NS_ENSURE_SUCCESS(rv, rv);
1158 
1159  // Failure in album art transcoding is not fatal, we just skip the
1160  // art in that case.
1161 
1162  // When passed a zero-length array of imageFormats, this just passes through
1163  // the image data when we ask for the transcoded art.
1164  rv = albumArt->Init(aRequest->item, imageFormats);
1165  if (NS_SUCCEEDED(rv)) {
1166  nsCOMPtr<nsIInputStream> imageStream;
1167  rv = albumArt->GetTranscodedArt(getter_AddRefs(imageStream));
1168  if (imageStream && NS_SUCCEEDED(rv)) {
1169  rv = proxiedJob->SetMetadataImage(imageStream);
1170  if (NS_FAILED(rv))
1171  NS_WARNING("Setting metadata image failed");
1172  }
1173  }
1174 
1175  typedef sbTranscodeProgressListener::StatusProperty StatusProperty;
1176 
1177  StatusProperty statusProperty(source,
1178  NS_LITERAL_STRING(SB_PROPERTY_CDRIP_STATUS));
1179 
1180  nsCOMPtr<sbIJobCancelable> cancel = do_QueryInterface(proxiedJob);
1181 
1182  PRMonitor * const stopWaitMonitor =
1183  mRequestThreadQueue->GetStopWaitMonitor();
1184 
1185  // Create our listener for transcode progress.
1186  nsRefPtr<sbTranscodeProgressListener> listener =
1188  mStatus,
1189  aRequest->item,
1190  stopWaitMonitor,
1191  statusProperty,
1192  cancel);
1193  NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
1194 
1195  // Setup the progress listener.
1196  nsCOMPtr<sbIJobProgress> progress = do_QueryInterface(proxiedJob, &rv);
1197  NS_ENSURE_SUCCESS(rv, rv);
1198  rv = progress->AddJobProgressListener(listener);
1199  NS_ENSURE_SUCCESS(rv, rv);
1200 
1201  // Setup the mediacore event listener.
1202  nsCOMPtr<sbIMediacoreEventTarget> eventTarget = do_QueryInterface(proxiedJob,
1203  &rv);
1204  NS_ENSURE_SUCCESS(rv, rv);
1205  rv = eventTarget->AddListener(listener);
1206  NS_ENSURE_SUCCESS(rv, rv);
1207 
1208  // This is async.
1209  rv = proxiedJob->Transcode();
1210  NS_ENSURE_SUCCESS(rv, rv);
1211 
1212  // Wait until the transcode job is complete.
1213  PRBool isComplete = PR_FALSE;
1214  while (!isComplete) {
1215  // Operate within the request wait monitor.
1216  nsAutoMonitor monitor(stopWaitMonitor);
1217 
1218  // Check if the job is complete.
1219  isComplete = listener->IsComplete();
1220 
1221  // If not complete, wait for completion.
1222  if (!isComplete)
1223  monitor.Wait();
1224  }
1225 
1226  if (listener->IsAborted()) {
1227  autoComplete.SetResult(NS_OK);
1228  HandleRipEnd();
1229  return NS_ERROR_ABORT;
1230  }
1231 
1232  // Check the transcode status.
1233  PRUint16 status;
1234  rv = progress->GetStatus(&status);
1235  NS_ENSURE_SUCCESS(rv, rv);
1236 
1237  // Log any errors.
1238 #ifdef PR_LOGGING
1239  if (status != sbIJobProgress::STATUS_SUCCEEDED) {
1240  // Get an enumerator of the error messages.
1241  nsCOMPtr<nsIStringEnumerator> errorMessageEnum;
1242  rv = progress->GetErrorMessages(getter_AddRefs(errorMessageEnum));
1243 
1244  // Log each error.
1245  if (NS_SUCCEEDED(rv)) {
1246  PRBool hasMore;
1247  rv = errorMessageEnum->HasMore(&hasMore);
1248  if (NS_FAILED(rv))
1249  hasMore = PR_FALSE;
1250  while (hasMore) {
1251  // Get the next error message.
1252  nsAutoString errorMessage;
1253  rv = errorMessageEnum->GetNext(errorMessage);
1254  if (NS_FAILED(rv))
1255  break;
1256 
1257  // Log the error message.
1258  LOG("sbCDDevice::ReqTranscodeWrite error %s\n",
1259  NS_ConvertUTF16toUTF8(errorMessage).get());
1260 
1261  // Check for more error messages.
1262  rv = errorMessageEnum->HasMore(&hasMore);
1263  if (NS_FAILED(rv))
1264  hasMore = PR_FALSE;
1265  }
1266  }
1267  }
1268 #endif
1269 
1270  if (status == sbIJobProgress::STATUS_SUCCEEDED) {
1271  // Update the destination item content length.
1272  sbLibraryUtils::GetContentLength(destination);
1273 
1274  // Show the destination item.
1275  rv = destination->SetProperty(NS_LITERAL_STRING(SB_PROPERTY_HIDDEN),
1276  NS_LITERAL_STRING("0"));
1277  NS_ENSURE_SUCCESS(rv, rv);
1278 
1279  // Clear auto-removal of media file.
1280  autoRemoveMediaFile.forget();
1281 
1282  autoComplete.SetResult(NS_OK);
1283  }
1284  else {
1285  // Return failure after cleaning up at the bottom of this method.
1286  rv = NS_ERROR_FAILURE;
1287  }
1288 
1289  const PRUint32 batchIndex = aRequest->GetBatchIndex() + 1;
1290 
1291  // We need to check if this is the last item to be ripped, if so check for
1292  // AutoEject.
1293  if (batchIndex == aBatchCount) {
1294  nsresult rv2;
1295  mTranscodeProfile = nsnull;
1296 
1297  rv2 = HandleRipEnd();
1298  NS_ENSURE_SUCCESS(rv2, rv2);
1299  }
1300 
1301  return rv;
1302 }
1303 
const unsigned long EVENT_CDLOOKUP_METADATA_COMPLETE
classDescription entry
Definition: FeedWriter.js:1427
static nsresult GetTranscodedFileExtension(sbITranscodeProfile *aProfile, nsCString &aExtension)
#define SB_PROPERTY_SHOULDRIP
var args
Definition: alert.js:8
nsresult CreateAndDispatchEvent(PRUint32 aType, nsIVariant *aData, PRBool aAsync=PR_TRUE, sbIDeviceEventTarget *aTarget=nsnull)
#define SB_PRLOG_SETUP(x)
Definition: sbDebugUtils.h:115
return NS_OK
#define SB_PROPERTY_CDRIP_STATUS
SB_AUTO_CLASS2(sbCDAutoIgnoreItem, sbCDDevice *, sbIMediaItem *, mValue!=nsnull, mValue->UnignoreMediaItem(mValue2), mValue=nsnull)
const unsigned long REQUEST_CDLOOKUP
static nsresult GetContentLength(sbIMediaItem *aItem, PRInt64 *_retval=nsnull)
nsAutoPtr< sbDeviceStatusHelper > mStatus
Definition: sbBaseDevice.h:689
#define SB_PROPERTY_ORIGINLIBRARYGUID
#define SB_PROPERTY_SAMPLERATE
#define LOG(args)
#define MULTI_CD_INFO_FOUND_DIALOG_URI
#define SB_PROPERTY_CHANNELS
nsRefPtr< sbDeviceRequestThreadQueue > mRequestThreadQueue
Definition: sbBaseDevice.h:730
#define PREF_CDDEVICE_AUTOEJECT
Definition: sbCDDevice.h:126
static nsresult BulkSetProperty(sbIMediaList *aMediaList, const nsAString &aPropertyId, const nsAString &aPropertyValue, sbIPropertyArray *aPropertyFilter=nsnull, PRInt32 *aAbortFlag=nsnull)
const unsigned long EVENT_CDLOOKUP_COMPLETED
Generic interface for exposing long running jobs to the UI.
#define SB_THREADSAFE_ARRAY_CONTRACTID
Definition: sbArrayUtils.h:40
const NS_ERROR_ABORT
#define SB_CD_DEVICE_AUTO_INVOKE(aName, aMethod)
#define SB_PROPERTY_HIDDEN
const unsigned long TRANSCODE_TYPE_AUDIO
#define SB_MUTABLEPROPERTYARRAY_CONTRACTID
const unsigned short STATUS_SUCCEEDED
Constant indicating that the job has completed.
nsresult do_GetProxyForObject(nsIEventTarget *aTarget, REFNSIID aIID, nsISupports *aObj, PRInt32 aProxyType, void **aProxyObject)
Songbird Variant Utility Definitions.
static nsresult GetContentURI(nsIURI *aURI, nsIURI **_retval, nsIIOService *aIOService=nsnull)
Return a library content URI for the URI specified by aURI. A library content URI is a specially form...
#define NO_CD_INFO_FOUND_DIALOG_URI
#define SB_PROPERTY_BITRATE
sbDeviceTranscoding * GetDeviceTranscoding() const
Definition: sbBaseDevice.h:619
const unsigned short STATUS_RUNNING
Constant indicating that the job is active.
nsresult GetDeviceTranscodingProperty(PRUint32 aTranscodeType, const nsAString &aPropertyName, nsIVariant **aPropertyValue)
#define PREF_CDDEVICE_RIPBRANCH
Definition: sbCDDevice.h:125
#define SONGBIRD_TRANSCODEALBUMART_CONTRACTID
_hideDatepicker duration
const sbCreateProxiedComponent do_ProxiedGetService(const nsCID &aCID, nsresult *error=0)
NS_IMETHOD Eject(void)
RequestItems::const_iterator const_iterator
nsresult RegenerateMediaURL(sbIMediaItem *aItem, nsIURI **_retval)
#define SB_PROPERTY_CDDISCHASH
static nsresult GetProperty(nsIPropertyBag2 *aProperties, nsAString const &aProp, nsAString &aValue)
#define SB_PROPERTY_DURATION
this _document this
Definition: FeedWriter.js:1085
const unsigned long STATE_IDLE
Definition: sbIDevice.idl:220
NS_IMETHOD Disconnect()
SB_AUTO_NULL_CLASS(sbCDAutoFalse, PRBool *,*mValue=PR_FALSE)
#define PREF_CDDEVICE_NOTIFYSOUND
Definition: sbCDDevice.h:127
nsresult SetIgnoreMediaListListeners(PRBool aIgnoreListener)
const unsigned long STATE_MOUNTING
Definition: sbIDevice.idl:226
const unsigned long STATE_TRANSCODE
Definition: sbIDevice.idl:235
const unsigned long STATE_LOOKINGUPCD
PRBool mConnected
Definition: sbBaseDevice.h:728
return
Definition: FeedWriter.js:850
static sbTranscodeProgressListener * New(sbBaseDevice *aDeviceBase, sbDeviceStatusHelper *aDeviceStatusHelper, sbIMediaItem *aItem, PRMonitor *aCompleteNotifyMonitor=nsnull, StatusProperty const &aStatusProperty=StatusProperty(), sbIJobCancelable *aCancel=nsnull)
nsresult SetIgnoreLibraryListener(PRBool aIgnoreListener)
const unsigned short TRACKMODE_AUDIO
Definition: sbICDDevice.idl:46
var uri
Definition: FeedWriter.js:1135
StringArrayEnumerator prototype hasMore
countRef value
Definition: FeedWriter.js:1423
#define SB_PROPERTY_ALBUMNAME
nsresult CreateUniqueMediaFile(nsIURI *aFileURI, nsIFile **aUniqueFile, nsIURI **aUniqueFileURI)
static void AppendInt(nsAString &str, PRInt64 val)
Songbird Device Status Services Definitions.
if(DEBUG_DATAREMOTES)
Implemented to receive notifications from sbIJobProgress interfaces.
const unsigned long EVENT_CDLOOKUP_INITIATED
Interface that defines a single item of media in the system.
#define SB_PROPERTY_TRACKNAME
nsresult GetVolumeForItem(sbIMediaItem *aItem, sbBaseDeviceVolume **aVolume)
#define SB_PROPERTY_AVAILABILITY
const unsigned short STATUS_FAILED
Constant indicating that the job has completed with errors.
#define SB_PROPERTY_ORIGINITEMGUID
_getSelectedPageStyle s i
sbCDAutoDeviceLocker(sbICDDevice *aCDDevice)
virtual PRBool IsRequestAborted()
Definition: sbCDDevice.cpp:979
nsresult SelectTranscodeProfile(PRUint32 aTranscodeType, sbITranscodeProfile **aProfile)
Select a transcode profile to use when transcoding to this device.
#define SB_PROPERTY_TRACKNUMBER
nsresult AddLibrary(sbIDeviceLibrary *aDevLib)