OSDN Git Service

ファイルロード時の進捗をプログレスバーで表示するようにした。
authorSFPGMR <sfpg@git.sourceforge.jp>
Sat, 16 Apr 2011 22:22:13 +0000 (07:22 +0900)
committerSFPGMR <sfpg@git.sourceforge.jp>
Sat, 16 Apr 2011 22:22:13 +0000 (07:22 +0900)
geturl_handler.cc
geturl_handler.h
xm_player.cc
xm_player.html

index 633b74f..7dc59dd 100644 (file)
 #include <boost/format.hpp>
 #include <string>
 #include <vector>
+#include <boost/xpressive/xpressive.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace  x = boost::xpressive;
 
 extern void LogMsg (void* instance,const char* format,...);
 
@@ -26,18 +30,18 @@ bool IsError(int32_t result) {
 std::string GetURLHandler::js_empty_;
 
 GetURLHandler* GetURLHandler::Create(pp::Instance* instance,
-                                     const std::string& url,std::vector<char>& result_data,const std::string& jsFuncName ) {
-  return new GetURLHandler(instance, url,result_data,jsFuncName);
+                                     const std::string& url,std::vector<char>& result_data,const std::string& jsFuncName,complete_func_type func ) {
+  return new GetURLHandler(instance, url,result_data,jsFuncName,func);
 }
 
 GetURLHandler::GetURLHandler(pp::Instance* instance,
-                             const std::string& url,std::vector<char>& result_data,const std::string& jsFuncName)
+                             const std::string& url,std::vector<char>& result_data,const std::string& jsFuncName,complete_func_type func)
     : instance_(instance),
       url_(url),
       url_request_(instance),
       url_loader_(instance),
       url_response_body_(result_data),
-      cc_factory_(this) {
+      cc_factory_(this),load_success_(false) ,received_bytes_(0),total_bytes_(0),func_(func),status_(init){
     if(jsFuncName == "")
     {
       js_func_name_ = js_empty_;
@@ -54,9 +58,9 @@ GetURLHandler::~GetURLHandler() {
 }
 
 bool GetURLHandler::Start() {
+  LogMsg(instance_,"GetURLHandler::Start () Enter" );
   pp::CompletionCallback cc = cc_factory_.NewCallback(&GetURLHandler::OnOpen);
   int32_t res = url_loader_.Open(url_request_, cc);
-  pp::URLResponseInfo info(url_loader_.GetResponseInfo());
   LogMsg(instance_,"GetURLHandler::Start::result = %d",res);
   if ((PP_ERROR_WOULDBLOCK) != res )
     cc.Run(res);
@@ -65,45 +69,66 @@ bool GetURLHandler::Start() {
 }
 
 void GetURLHandler::OnOpen(int32_t result) {
-  result_ = result;
+  LogMsg(instance_,"GetURLHandler::OnOpen::result = %d",result);
   pp::URLResponseInfo info(url_loader_.GetResponseInfo());
   LogMsg(instance_,"GetURLHandler::OnOpen::result = %d,Status Code = %d",result,info.GetStatusCode());
-  
+  LogMsg(instance_,"Headers: %s",info.GetProperty(PP_URLRESPONSEPROPERTY_HEADERS).AsString().c_str());
   if (result < 0 || info.GetStatusCode() >= 400){
     std::string result_str((boost::format("pp::URLLoader::Open() failed: %d %s") % result % info.GetStatusLine().AsString()).str());
     LogMsg(instance_, result_str.c_str());
+    func_(open,false,*this);
     CallbackEventJS(open,false,result_str);
-    delete this;
-//    ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false);
+    status_ = end;
+    //    ReportResultAndDie(url_, "pp::URLLoader::Open() failed", false);
   } else {
+    x::sregex  reg =  "Content-Length: "  >> ( x::s1 = +x::_d ) ;
+    //x::sregex reg = x::sregex::compile("Content\\-Length\\:\\s([0-9]+)\\s");
+    x::smatch m;
+    if(x::regex_search(info.GetProperty(PP_URLRESPONSEPROPERTY_HEADERS).AsString(),m,reg))
+    {
+      LogMsg(instance_, "regex:match() success");
+      total_bytes_ = boost::lexical_cast<int32_t>(m[1].str());
+    };
     LogMsg(instance_, "pp::URLLoader::Open() Success.");
-    CallbackEventJS(open,true);
+    CallbackEventJS(open,true,pp::Var((int32_t)total_bytes_));
+    status_ = open;
+    func_(open,true,*this);
     ReadBody();
   }
 }
 
 void GetURLHandler::OnRead(int32_t result) {
   result_ = result;
-  if (result < 0) {
-    std::string result_str((boost::format("pp::URLLoader::OnRead() file: %s result: %d") % url_.c_str() % result).str());
-    LogMsg(instance_, result_str.c_str());
-    CallbackEventJS(loading,false,result_str);
-    delete this;
-  } else if (result != 0) {
+  pp::URLResponseInfo info(url_loader_.GetResponseInfo());
+
+  if (result < 0 && info.GetStatusCode() >= 400) {
+    // \83G\83\89\81[\8f\88\97\9d
+    result_string_ =  (boost::format("pp::URLLoader::OnRead() file: %s result: %d status code:%d") % url_.c_str() % result %  info.GetStatusCode()).str();
+    LogMsg(instance_, result_string_.c_str());
+    load_success_ = false;
+    CallbackEventJS(loading,load_success_,result_string_);
+    func_(loading,load_success_,*this);
+    status_ = end;
+  } else if (result != 0 ) {
     /*\83X\83e\81[\83^\83X\83R\81[\83h\83`\83F\83b\83N*/
-      pp::URLResponseInfo info(url_loader_.GetResponseInfo());
-      int32_t num_bytes = result < kBufferSize ? result : sizeof(buffer_);
-      url_response_body_.reserve(url_response_body_.size() + num_bytes);
-      url_response_body_.insert(url_response_body_.end(),
+      
+    int32_t num_bytes = result < kBufferSize ? result : sizeof(buffer_);
+    url_response_body_.reserve(url_response_body_.size() + num_bytes);
+    url_response_body_.insert(url_response_body_.end(),
                                 buffer_,
                                 buffer_ + num_bytes);
+
+    //pp::FileRef_Dev d(info.
+      //url_loader_.GetDownloadProgress(&received_bytes_,&total_bytes_);
+      received_bytes_ += num_bytes;
       LogMsg(instance_,"pp::URLLoader::OnRead() File: %s Success: %d bytes Status: %d" ,url_.c_str(),num_bytes,info.GetStatusCode());
       ReadBody();
   } else {  // result == 0, end of stream
-    isLoadSuccess = true;
+    load_success_ = true;
     LogMsg(instance_,"Load Success. File Size is %d bytes.\n",url_response_body_.size());
-    CallbackEventJS(complete,true,(int32_t)(url_response_body_.size()));
-    delete this;
+    CallbackEventJS(complete,load_success_,(int32_t)(url_response_body_.size()));
+    func_(complete,load_success_,*this);
+    status_ = end;
   }
 }
 /* TODO: \90i\92»\8fó\91Ô\82Ì\93Ç\82Ý\8eæ\82è\82ð\8dì\82é */
index be1e3c4..b2cecae 100644 (file)
@@ -9,6 +9,7 @@
 #include <ppapi/cpp/url_loader.h>
 #include <ppapi/cpp/url_request_info.h>
 #include <ppapi/cpp/instance.h>
+#include <boost/function.hpp>
 
 // GetURLHandler is used to download data from |url|. When download is
 // finished or when an error occurs, it calls JavaScript function
 //
 class GetURLHandler {
  public:
-   enum  event_id {
+
+   enum  status_id {
       open,
       loading,
-      complete
+      complete,
+      end,
+       init
    };
+
+   typedef boost::function<void (status_id,bool,GetURLHandler&) > complete_func_type;
+   static void null_func(status_id,bool,GetURLHandler&) { } ;
+
   // Creates instance of GetURLHandler on the heap.
   // GetURLHandler objects shall be created only on the heap (they
   // self-destroy when all data is in).
   static GetURLHandler* Create(pp::Instance* instance_,
-                               const std::string& url,std::vector<char>& result,const std::string& jsFuncName = js_empty_);
+                               const std::string& url,std::vector<char>& result,const std::string& jsFuncName = js_empty_,complete_func_type func = complete_func_type(&null_func));
   // Initiates page (URL) download.
   // Returns false in case of internal error, and self-destroys.
   bool Start();
 
- private:
-  static const int kBufferSize = 4096;
+  int32_t GetReceivedBytes() const
+  {
+    return (int32_t)received_bytes_;
+  }
+
+  int32_t GetTotalBytes() const 
+  {
+    return (int32_t)total_bytes_;
+  }
 
-  GetURLHandler(pp::Instance* instance_, const std::string& url,std::vector<char>& result,const std::string& jsFuncName = js_empty_);
   ~GetURLHandler();
+  status_id GetStatus() const { return status_;};
+private:
+  static const int kBufferSize = 4096;
+
+  GetURLHandler(pp::Instance* instance_, const std::string& url,std::vector<char>& result,const std::string& jsFuncName = js_empty_,complete_func_type func = complete_func_type(&null_func));
 
   // Callback fo the pp::URLLoader::Open().
   // Called by pp::URLLoader when response headers are received or when an
@@ -59,7 +78,7 @@ class GetURLHandler {
   // OnRead() will be called when bytes are received or when an error occurs.
   void ReadBody();
 
-  void CallbackEventJS(event_id id,bool status,const pp::Var& reason = std::string(""))
+  void CallbackEventJS(status_id id,bool status,const pp::Var& reason = std::string(""))
   {
     if(!js_func_name_.empty())
     {
@@ -78,7 +97,7 @@ class GetURLHandler {
   //                        const std::string& text,
   //                        bool success);
 
-   pp::Instance* instance_;
+  pp::Instance* instance_;
   std::string url_;  // URL to be downloaded.
   pp::URLRequestInfo url_request_;
   pp::URLLoader url_loader_;  // URLLoader provides an API to download URLs.
@@ -87,10 +106,14 @@ class GetURLHandler {
   pp::CompletionCallbackFactory<GetURLHandler> cc_factory_;
   std::string js_func_name_;
   uint32_t result_;
-  bool isLoadSuccess;
+  std::string result_string_;
+  bool load_success_;
     GetURLHandler(const GetURLHandler&);
   void operator=(const GetURLHandler&);
   static std::string js_empty_;
+  int64_t received_bytes_,total_bytes_;
+  complete_func_type func_;
+  status_id status_;
 };
 
 #endif  // EXAMPLES_GETURL_GETURL_HANDLER_H_
index b3d1848..3636d00 100644 (file)
@@ -36,8 +36,11 @@ namespace {
   const char* const kStopSoundId = "stopSound";
   // メインスレッド以外のログを取得する
   const char* const kGetLogId = "getLog";
-  //  
+ //
   const char* const kCheckLogId = "checkLog";
+  const char * const kRecievedBytesId = "receivedBytes";
+  const char * const kTotalBytesId = "totalBytes";
+
  // システムにリクエストするサンプルカウント数
 const uint32_t kSampleFrameCount = 4096u;
 // 現在サポートしているのはステレオオーディオのみである。
@@ -122,10 +125,14 @@ class XmPlayerInstance : public pp::Instance {
       : pp::Instance(instance), scriptable_object_(NULL),
         sample_frame_count_(kSampleFrameCount)  , mod_( MOD__Create(this))
   {
-    pthread_mutex_init(&mutex_, NULL);
+    pthread_mutexattr_init(&mutex_attr_);
+    pthread_mutexattr_settype(&mutex_attr_,PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&mutex_, NULL );
   }
   virtual ~XmPlayerInstance() 
   {
+    pthread_mutex_destroy(&mutex_);
+    pthread_mutexattr_destroy(&mutex_attr_);
     MOD__Destruct(mod_);
   }
 
@@ -187,7 +194,7 @@ class XmPlayerInstance : public pp::Instance {
     }
     std::string ret(log_.front());
     {
-      ScopedMutexLock lock(&mutex_);
+     ScopedMutexLock lock(&mutex_);
       log_.pop_front();
     }
     return ret;
@@ -199,6 +206,43 @@ class XmPlayerInstance : public pp::Instance {
     pp::Var exception;
     window.Call("reportLog",log, &exception);
   }
+
+  bool LoadXmFile(const std::string& url,const std::string& jsFuncName)
+  {
+     SendLog("XmPlayerInstance::LoadXmFile()::CreateGetURLHandler");
+    //MODファイルのロード
+   { //GetURLHandler *handler_ = 0;
+    if(!handler_  || handler_->GetStatus() == GetURLHandler::end){
+       handler_.reset(GetURLHandler::Create(this,url,GetLoadData(),jsFuncName));
+      // handler_= GetURLHandler::Create(this,url,GetLoadData(),jsFuncName);
+      if(!handler_)
+      {
+          return false;
+      }
+    } else {
+      return false;
+    }
+    SendLog("XmPlayerInstance::LoadXmFile()::handler_->Start()");
+    if(!handler_->Start()){
+      return false;
+    };
+    SendLog("XmPlayerInstance::LoadXmFile() Exit");
+    return true;
+   }
+  }
+
+  int32_t GetReceivedBytes()
+  {
+    if(!handler_) return 0;
+     return  handler_->GetReceivedBytes();
+  }
+
+  int32_t GetTotalBytes()
+  {
+    if(!handler_) return 0;
+    return  handler_->GetTotalBytes();
+  }
+
  private:
   static void XmPlayerCallback(void* samples, size_t buffer_size, void* data) {
     XmPlayerInstance* xm_player_instance =
@@ -222,6 +266,8 @@ class XmPlayerInstance : public pp::Instance {
   std::vector<char> load_data_;
   std::list<std::string> log_;
   pthread_mutex_t mutex_;
+  pthread_mutexattr_t mutex_attr_;
+  boost::shared_ptr<GetURLHandler> handler_; 
 };
 
 // The Module class.  The browser calls the CreateInstance() method to create
@@ -284,13 +330,12 @@ bool XmPlayerScriptableObject::HasMethod(const pp::Var& method,
 
 bool XmPlayerScriptableObject::HasProperty(const pp::Var& property,
                                             pp::Var* exception) {
-  return false;
-  //                                            if (!property.is_string()) {
-  //  return false;
-  //}
-  //const std::string property_name = property.AsString();
-  //const bool has_property = (property_name == kFrequencyId);
-  //return has_property;
+  if (!property.is_string()) {
+    return false;
+  }
+  const std::string property_name = property.AsString();
+  const bool has_property = (property_name == kRecievedBytesId) || (property_name == kTotalBytesId);
+  return has_property;
 }
 
 void XmPlayerScriptableObject::SetProperty(const pp::Var& property,
@@ -338,9 +383,12 @@ pp::Var XmPlayerScriptableObject::GetProperty(const pp::Var& property,
     return pp::Var();
   }
   std::string property_name = property.AsString();
-  //if (property_name == kFrequencyId) {
-  //  return pp::Var(frequency());
-  //}
+  if (property_name == kRecievedBytesId) {
+    return pp::Var(player_.GetReceivedBytes());
+  } else if(property_name == kTotalBytesId)
+  {
+    return pp::Var(player_.GetTotalBytes());
+  }
   *exception = std::string("No property named ") + property_name;
   return pp::Var();
 }
@@ -357,18 +405,8 @@ pp::Var XmPlayerScriptableObject::GetProperty(const pp::Var& property,
 
   bool XmPlayerScriptableObject::LoadXmFile(const std::string& url,const std::string& jsFuncName)
   {
-    //MODファイルのロード
-   GetURLHandler* handler_(GetURLHandler::Create(&player_,url,player_.GetLoadData(),jsFuncName));
-   if(handler_)
-   {
-     if(!handler_->Start()){
-       return false;
-     };
-   } else {
-     return false;
+    return player_.LoadXmFile(url,jsFuncName);
    }
-   return true;
-  }
 }  // namespace xm_player
 
 void LogMsg (void* instance,const char* format,...)
@@ -380,7 +418,8 @@ void LogMsg (void* instance,const char* format,...)
   va_end(ap);
 
   //pp::Instance * inst = pp::Module::Get()->InstanceForPPInstance(instance);
- xm_player::XmPlayerInstance * inst = reinterpret_cast<xm_player::XmPlayerInstance*>(instance);
+ xm_player::XmPlayerInstance * inst = static_cast<xm_player::XmPlayerInstance*>(instance);
+ //inst->SendLog(buf);
  inst->WriteLog(buf);
  // pp::Var window(inst->GetWindowObject());
   //window.is_int();
index c6ce36c..359752e 100644 (file)
@@ -19,24 +19,24 @@ found in the LICENSE file.
 <script type="text/javascript" src="http://nacl-gallery.appspot.com/check_browser.js"></script> 
 <!-- <script type="text/javascript" src="jquery-1.5.1.min.js"></script> -->
 <script type="text/javascript">
-<script type="text/javascript">
-  var _gaq = _gaq || [];
-  _gaq.push(['_setAccount', 'UA-15457703-9']);
-  _gaq.push(['_trackPageview']);
-
-  (function() {
-    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
-    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
-    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
-  })();
-</script>
-  <script type="text/javascript">
+//    var _gaq = _gaq || [];
+//    _gaq.push(['_setAccount', 'UA-15457703-9']);
+//    _gaq.push(['_trackPageview']);
+
+//    (function() {
+//      var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+//      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+//      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+//    })();
+
     var xmPlayer = null;  // Global application object.
     var timerId = null;
+    var progress_id = null;
     var reportResult;
     var status_open = 0;
     var status_loading = 1;
     var status_complete = 2;
+    var total_bytes = 0;
     function reportLog(log) {
 //      $("#GeneralOutput").append(log + "<br/>");
       var logElt = document.getElementById('GeneralOutput');
@@ -93,14 +93,46 @@ found in the LICENSE file.
     function moduleLoad() {
       xmPlayer = document.getElementById("xmPlayer");
 
+      timerId = setInterval(function () {
+        if (xmPlayer.checkLog()) {
+          var c = $("#GeneralOutput");
+          while (xmPlayer.checkLog()) {
+            c.append(xmPlayer.getLog() + "<br/>");
+          }
+        }
+      }, 300);
+
       $("#load-file").attr("disabled", "").click(
         function () {
           try {
+            var logElt = document.getElementById('GeneralOutput');
+
             reportResult = function (status, success, result) {
               var logElt = document.getElementById('GeneralOutput');
               logElt.innerHTML += 'File URL:' + $("#xmfile-url").val() + '<br/>';
               logElt.innerHTML += 'RESULT:\n' + result + '<br/>';
+
+              // ファイルオープンが成功したら
+              if (status == status_open && success) {
+                // トータルバイト数を取得する
+                total_bytes = parseInt(result);
+                logElt.innerHTML += "TotalBytes:" + total_bytes + '<br/>';
+                $("#status-dialog")
+                  .html("<p>ファイルを読み込んでいます。</p><div id='progress'></div>")
+                  .attr("title", "ファイルロード")
+                  .dialog();
+
+                $("#progress").progressbar({ value: 0 });
+                // 100ms 毎に進捗を表示
+                progress_id = setInterval(function () {
+                  $("GeneralOutput").append(xmPlayer.receivedBytes + "<br/>");
+                  $("#progress").progressbar("value", parseInt(xmPlayer.receivedBytes * 100 / total_bytes));
+                }, 100);
+              }
+
               if (status == status_complete && success) {
+                if (progress_id != null)
+                  clearInterval(progress_id);
                 $("#Play").click(function () {
                   xmPlayer.playSound();
                 }).attr("disabled", "");
@@ -108,26 +140,25 @@ found in the LICENSE file.
                 $("#Stop").click(function () {
                   xmPlayer.stopSound();
                 }).attr("disabled", "");
-                $("#status-dialog").html("ファイルの読み込みが完了しました。")
-                .attr("title", "ファイルロード")
+
+                $("#status-dialog")
+                .html("ファイルの読み込みが完了しました。")
                 .dialog({ buttons: [
                   {
-                    text: "Ok",
-                    click: function () { $(this).dialog("close"); }
-                  }
-                ]
+                    text: "Ok", click: function () { $(this).dialog("close"); }
+                  }]
                 });
               } else if (!success) {
+                if (progress_id != null)
+                  clearInterval(progress_id);
                 logElt.innerHTML += "Load Failure:" + result + "<br/>";
                 $("#status-dialog").html("ファイルの読み込みが失敗しました。" + result)
                 .attr("title", "ファイルロード")
-                .dialog({ buttons: [
+                .dialog("options", "buttons", [
                   {
-                    text: "Ok",
-                    click: function () { $(this).dialog("close"); }
-                  }
-                ]
-                });
+                    text: "Ok", click: function () { $(this).dialog("close"); }
+                  }]
+                );
               }
             };
 
@@ -142,14 +173,7 @@ found in the LICENSE file.
         }
         );
 
-        timerId = setInterval(function () {
-          if (xmPlayer.checkLog()) {
-            var c = $("#GeneralOutput");
-            while (xmPlayer.checkLog()) {
-              c.append(xmPlayer.getLog() + "<br/>");
-            }
-          }
-        }, 300);
+
       }
 
   </script>
@@ -181,6 +205,7 @@ found in the LICENSE file.
   <option value="SHADOW.XM">SHADOW.XM</option>
   <option value="DEADLOCK.XM">DEADLOCK.XM</option>
   <option value="sweetdre.xm">sweetdre.xm</option>
+  <option value="aws_aq16.xm">aws_aq16.xm</option>
   </select></div>
  <!-- <input id="xmfile-url" type="text" maxlength="2048" /></div> -->
   <div>
@@ -211,6 +236,6 @@ found in the LICENSE file.
          type="application/x-nacl"
          onload="moduleLoad();"
  />
- <div id="status-dialog" title=""></div>
+ <div id="status-dialog" title=""><p>これはこれは</p></div>
  </body>
 </html>