Bug 1180589 part 2 - Add creating mediastream code. r=seanlin
authorMantaroh Yoshinaga <mantaroh@gmail.com>
Tue, 29 Sep 2015 13:22:25 +0900
changeset 264882 b4185d03b6d59db6b78191e0210c87df39bc524b
parent 264881 4867b986b2c788e1ec687266eee5edc8dc672443
child 264883 31392a3bfe2a6da206c6cfdaff8dcc32d989e2b6
push id65773
push userbbirtles@mozilla.com
push dateTue, 29 Sep 2015 04:23:03 +0000
treeherdermozilla-inbound@b4185d03b6d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseanlin
bugs1180589
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1180589 part 2 - Add creating mediastream code. r=seanlin
dom/tv/TVSimulatorService.js
dom/tv/TVSimulatorService.manifest
dom/tv/TVSource.cpp
dom/tv/TVTuner.cpp
dom/tv/TVTuner.h
dom/tv/nsITVSimulatorService.idl
--- a/dom/tv/TVSimulatorService.js
+++ b/dom/tv/TVSimulatorService.js
@@ -19,36 +19,32 @@ Cu.import("resource://gre/modules/XPCOMU
 function TVSimulatorService() {
   this._internalTuners = null;
   this._scanCompleteTimer = null;
   this._scanningWrapTunerData = null;
   this._init();
 }
 
 TVSimulatorService.prototype = {
-  classID: Components.ID("{f0ab9850-24b4-4f5d-83dd-0fea0c249ca1}"),
+  classID: Components.ID("{94b065ad-d45a-436a-b394-6dabc3cf110f}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsITVSimulatorService,
                                          Ci.nsITVService,
                                          Ci.nsITimerCallback]),
 
   _init: function TVSimInit() {
     if (this._internalTuners) {
       return;
     }
 
     // Load the setting file from local JSON file.
     // Synchrhronous File Reading.
-    let dsFile = Cc["@mozilla.org/file/directory_service;1"]
-                   .getService(Ci.nsIProperties)
-                   .get("ProfD", Ci.nsIFile);
-    dsFile.append(TV_SIMULATOR_DUMMY_DIRECTORY);
-    dsFile.append(TV_SIMULATOR_DUMMY_FILE);
     let file = Cc["@mozilla.org/file/local;1"]
                  .createInstance(Ci.nsILocalFile);
-    file.initWithPath(dsFile.path);
+
+    file.initWithPath(this._getFilePath(TV_SIMULATOR_DUMMY_FILE));
 
     let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
                     .createInstance(Ci.nsIFileInputStream);
     let cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]
                     .createInstance(Ci.nsIConverterInputStream);
 
     let settingStr = "";
 
@@ -92,17 +88,17 @@ TVSimulatorService.prototype = {
        *          "networkId":          "The ID of the channel network",
        *          "transportStreamId":  "The ID of channel transport stream",
        *          "serviceId":          "The ID of channel service",
        *          "type":               "The type of channel",
        *          "name":               "The channel name",
        *          "number" :            The LCN (Logical Channel Number) of the channel,
        *          "isEmergency" :       Whether this channel is emergency status,
        *          "isFree":             Whether this channel is free or not,
-       *          "videoFilePath":      "The path of the fake movie file",
+       *          "videoFilePath":      "The path of the fake video file",
        *          "programs":[{
        *            "eventId":          "The ID of this program event",
        *            "title" :           "This program's title",
        *            "startTime":        "The start time of this program",
        *            "duration":         "The duration of this program",
        *            "description":      "The description of this program",
        *            "rating":           "The rating of this program",
        *            "audioLanugages":   ["The array of audio language"],
@@ -217,18 +213,16 @@ TVSimulatorService.prototype = {
       debug("aCallback is null\n");
       return NS_ERROR_INVALID_ARG;
     }
 
     let wrapTunerData = this._getWrapTunerData(aTunerId, aSourceType);
     if (!wrapTunerData) {
       return aCallback.notifyError(Ci.nsITVServiceCallback.TV_ERROR_FAILURE);
     }
-
-    // Bug 1180589 : We should change video source.
     return aCallback.notifySuccess(null);
   },
 
   startScanningChannels: function TVSimStartScanningChannels(aTunerId, aSourceType, aCallback) {
     if (!aCallback) {
       debug("aCallback is null\n");
       return Cr.NS_ERROR_INVALID_ARG;
     }
@@ -394,30 +388,51 @@ TVSimulatorService.prototype = {
   set sourceListener(aListener) {
     this._sourceListener = aListener;
   },
 
   get sourceListener() {
       return this._sourceListener;
   },
 
-  getSimulatorVideoFilePath: function TVSimGetSimulatorVideoFilePath(aTunerId, aSourceType, aChannelNumber) {
+  getSimulatorVideoBlobURL: function TVSimGetSimulatorVideoBlob(aTunerId,
+                                                                aSourceType,
+                                                                aChannelNumber,
+                                                                aWin) {
     let wrapTunerData = this._getWrapTunerData(aTunerId, aSourceType);
-    if (!wrapTunerData || !wrapTunerData.channels || wrapTunerData.channels.size <= 0) {
-      return null;
+    if (!wrapTunerData || !wrapTunerData.channels) {
+      return "";
     }
 
-    return wrapTunerData.channels.get(aChannelNumber).videoFilePath;
+    let wrapChannelData = wrapTunerData.channels.get(aChannelNumber);
+    if (!wrapChannelData) {
+      return "";
+    }
+
+    let videoFile = new File(this._getFilePath(wrapChannelData.videoFilePath));
+    let videoBlobURL = aWin.URL.createObjectURL(videoFile);
+
+    return videoBlobURL;
   },
 
   _getTunerMapKey: function TVSimGetTunerMapKey(aTunerId, aSourceType) {
     return JSON.stringify({'tunerId': aTunerId, 'sourceType': aSourceType});
   },
 
   _getWrapTunerData: function TVSimGetWrapTunerData(aTunerId, aSourceType) {
     if (!this._internalTuners || this._internalTuners.size <= 0) {
       return null;
     }
     return this._internalTuners.get(this._getTunerMapKey(aTunerId, aSourceType));
-  }
+  },
+
+  _getFilePath: function TVSimGetFilePathFromDummyDirectory(fileName) {
+    let dsFile = Cc["@mozilla.org/file/directory_service;1"]
+                   .getService(Ci.nsIProperties)
+                   .get("ProfD", Ci.nsIFile);
+    dsFile.append(TV_SIMULATOR_DUMMY_DIRECTORY);
+    dsFile.append(fileName);
+
+    return dsFile.path;
+  },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TVSimulatorService]);
--- a/dom/tv/TVSimulatorService.manifest
+++ b/dom/tv/TVSimulatorService.manifest
@@ -1,3 +1,3 @@
-component {f0ab9850-24b4-4f5d-83dd-0fea0c249ca1} TVSimulatorService.js
-contract @mozilla.org/tv/simulatorservice;1 {f0ab9850-24b4-4f5d-83dd-0fea0c249ca1}
+component {94b065ad-d45a-436a-b394-6dabc3cf110f} TVSimulatorService.js
+contract @mozilla.org/tv/simulatorservice;1 {94b065ad-d45a-436a-b394-6dabc3cf110f}
 TVSimulatorService @mozilla.org/tv/simulatorservice;1
--- a/dom/tv/TVSource.cpp
+++ b/dom/tv/TVSource.cpp
@@ -128,16 +128,24 @@ TVSource::SetCurrentChannel(nsITVChannel
       // No actual change.
       return NS_OK;
     }
   }
 
   mCurrentChannel = TVChannel::Create(GetOwner(), this, aChannelData);
   NS_ENSURE_TRUE(mCurrentChannel, NS_ERROR_DOM_ABORT_ERR);
 
+  nsRefPtr<TVSource> currentSource = mTuner->GetCurrentSource();
+  if (currentSource && mType == currentSource->Type()) {
+    rv = mTuner->ReloadMediaStream();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
   return DispatchCurrentChannelChangedEvent(mCurrentChannel);
 }
 
 nsresult
 TVSource::UnsetCurrentChannel()
 {
   mCurrentChannel = nullptr;
   return DispatchCurrentChannelChangedEvent(mCurrentChannel);
--- a/dom/tv/TVTuner.cpp
+++ b/dom/tv/TVTuner.cpp
@@ -8,18 +8,20 @@
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/TVCurrentSourceChangedEvent.h"
 #include "mozilla/dom/TVServiceCallbacks.h"
 #include "mozilla/dom/TVServiceFactory.h"
 #include "mozilla/dom/TVSource.h"
 #include "mozilla/dom/TVUtils.h"
 #include "nsISupportsPrimitives.h"
 #include "nsITVService.h"
+#include "nsITVSimulatorService.h"
 #include "nsServiceManagerUtils.h"
 #include "TVTuner.h"
+#include "mozilla/dom/HTMLVideoElement.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(TVTuner, DOMEventTargetHelper,
                                    mTVService, mStream, mCurrentSource, mSources)
 
 NS_IMPL_ADDREF_INHERITED(TVTuner, DOMEventTargetHelper)
@@ -193,38 +195,118 @@ TVTuner::GetCurrentSource() const
 already_AddRefed<DOMMediaStream>
 TVTuner::GetStream() const
 {
   nsRefPtr<DOMMediaStream> stream = mStream;
   return stream.forget();
 }
 
 nsresult
+TVTuner::ReloadMediaStream()
+{
+  return InitMediaStream();
+}
+
+nsresult
 TVTuner::InitMediaStream()
 {
   nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(GetOwner());
   nsRefPtr<DOMMediaStream> stream = nullptr;
   if (mStreamType == nsITVTunerData::TV_STREAM_TYPE_HW) {
     stream = DOMHwMediaStream::CreateHwStream(window);
   } else if (mStreamType == nsITVTunerData::TV_STREAM_TYPE_SIMULATOR) {
-    // Bug 1180589 : We should MediaStream from local file.
-    //               We should create the PART.2 patch.
-    //stream = CreateSimulatedMediaStream();
-
-    return NS_OK;
+    stream = CreateSimulatedMediaStream();
   }
 
   mStream = stream.forget();
   return NS_OK;
 }
 
 already_AddRefed<DOMMediaStream>
 TVTuner::CreateSimulatedMediaStream()
 {
-  return nullptr;
+  ErrorResult error;
+
+  nsIDocument* doc = GetOwner()->GetExtantDoc();
+  if (NS_WARN_IF(!doc)) {
+    return nullptr;
+  }
+  nsRefPtr<Element> element = doc->CreateElement(VIDEO_TAG, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(element));
+  if (NS_WARN_IF(!content)) {
+    return nullptr;
+  }
+
+  HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(content.get());
+  if (NS_WARN_IF(!mediaElement)) {
+    return nullptr;
+  }
+
+  mediaElement->SetAutoplay(true, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return nullptr;
+  }
+
+  mediaElement->SetLoop(true, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIDOMWindow> domWin(do_QueryInterface(GetOwner()));
+  if (NS_WARN_IF(!domWin)) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsITVSimulatorService> simService(do_QueryInterface(mTVService));
+  if (NS_WARN_IF(!simService)) {
+    return nullptr;
+  }
+
+  if (NS_WARN_IF(!mCurrentSource)) {
+    return nullptr;
+  }
+
+  nsRefPtr<TVChannel> currentChannel = mCurrentSource->GetCurrentChannel();
+  if (NS_WARN_IF(!currentChannel)) {
+    return nullptr;
+  }
+
+  nsString currentChannelNumber;
+  currentChannel->GetNumber(currentChannelNumber);
+  if (currentChannelNumber.IsEmpty()) {
+    return nullptr;
+  }
+
+  nsString currentVideoBlobUrl;
+  nsresult rv = simService->GetSimulatorVideoBlobURL(mId,
+                                                     ToTVSourceTypeStr(mCurrentSource->Type()),
+                                                     currentChannelNumber,
+                                                     domWin,
+                                                     currentVideoBlobUrl);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  mediaElement->SetSrc(currentVideoBlobUrl, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return nullptr;
+  }
+
+  // See Media Capture from DOM Elements spec.
+  // http://www.w3.org/TR/mediacapture-fromelement/
+  nsRefPtr<DOMMediaStream> stream = mediaElement->MozCaptureStream(error);
+  if (NS_WARN_IF(error.Failed())) {
+    return nullptr;
+  }
+
+  return stream.forget();
 }
 
 nsresult
 TVTuner::DispatchCurrentSourceChangedEvent(TVSource* aSource)
 {
   TVCurrentSourceChangedEventInit init;
   init.mSource = aSource;
   nsCOMPtr<nsIDOMEvent> event =
--- a/dom/tv/TVTuner.h
+++ b/dom/tv/TVTuner.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_dom_TVTuner_h
 #define mozilla_dom_TVTuner_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 // Include TVTunerBinding.h since enum TVSourceType can't be forward declared.
 #include "mozilla/dom/TVTunerBinding.h"
 
+#define VIDEO_TAG NS_LITERAL_STRING("video")
+
 class nsITVService;
 class nsITVTunerData;
 
 namespace mozilla {
 
 class DOMMediaStream;
 
 namespace dom {
@@ -54,16 +56,18 @@ public:
   void GetId(nsAString& aId) const;
 
   already_AddRefed<TVSource> GetCurrentSource() const;
 
   already_AddRefed<DOMMediaStream> GetStream() const;
 
   IMPL_EVENT_HANDLER(currentsourcechanged);
 
+  nsresult ReloadMediaStream();
+
 private:
   explicit TVTuner(nsPIDOMWindow* aWindow);
 
   ~TVTuner();
 
   bool Init(nsITVTunerData* aData);
 
   nsresult InitMediaStream();
--- a/dom/tv/nsITVSimulatorService.idl
+++ b/dom/tv/nsITVSimulatorService.idl
@@ -1,28 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsITVService.idl"
+#include "nsIDOMWindow.idl"
 
 %{C++
 #define TV_SIMULATOR_SERVICE_CONTRACTID\
   "@mozilla.org/tv/simulatorservice;1"
 %}
 
-[scriptable, uuid(f0ab9850-24b4-4f5d-83dd-0fea0c249ca1)]
+[scriptable, uuid(8ecae67d-a959-4f8a-a786-14dc12bd8d3c)]
 interface nsITVSimulatorService : nsITVService
 {
   /*
-   * Get the simulate movie file.The path is full location path.
-   * e.g. /home/user/simulator/gaia/profile/dummy/tv-movie1.ogv
+   * Get the URL of simulated video blob.
    *
    * @param tunerId       The ID of the tuner.
    * @param sourceType    The source type to be used.
    * @param channelNumber The LCN (Logical Channel Number) of the channel.
+   * @param window        The window object of content.
+   * @return blobUrl      The URL of created blob from local video file.
    */
-  void getSimulatorVideoFilePath(in DOMString tunerId,
-                                 in DOMString sourceType,
-                                 in DOMString channelNumber,
-                                 [retval] out string filePath);
+  void getSimulatorVideoBlobURL(in DOMString tunerId,
+                                in DOMString sourceType,
+                                in DOMString channelNumber,
+                                in nsIDOMWindow window,
+                                [retval] out DOMString blobUrl);
 };