OSDN Git Service

b9098fda06a36d2bcdd88ed53e60c53f49112726
[nacltest/xmplayer.git] / xm_player.cc
1 // Copyright 2010 The Native Client Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can
3 // be found in the LICENSE file.
4 #include <stdio.h>
5
6 #include <ppapi/cpp/audio.h>
7 #include <ppapi/cpp/instance.h>
8 #include <ppapi/cpp/module.h>
9 #include <ppapi/cpp/completion_callback.h>
10 #include <ppapi/cpp/url_loader.h>
11 #include <ppapi/cpp/url_request_info.h>
12 #include <ppapi/cpp/dev/scriptable_object_deprecated.h>
13 #include <ppapi/cpp/var.h>
14
15 #include <cassert>
16 #include <cmath>
17 #include <limits>
18 #include <sstream>
19 #include <iostream>
20
21 #include "_mod.h"
22 #include "geturl_handler.h"
23 #include "boost/shared_ptr.hpp"
24 #include "boost/format.hpp"
25
26 namespace {
27   // XM ファイルのロード
28   const char* const kLoadXmFile = "loadXmFile";
29   // XM ファイルの再生コマンド文字列
30   const char* const kPlaySoundId = "playSound";
31   // XM ファイルの停止コマンド文字列
32   const char* const kStopSoundId = "stopSound";
33
34 // システムにリクエストするサンプルカウント数
35 const uint32_t kSampleFrameCount = 4096u;
36 // 現在サポートしているのはステレオオーディオのみである。
37 const uint32_t kChannels = 2u;
38 }  // namespace
39
40 namespace xm_player {
41 class XmPlayerInstance;
42  // このクラスはNaClモジュールのためのスクリプティング・インターフェースである。
43 // HasMethodメソッドはXmPlayerオブジェクトのメソッドが呼び出され、実行される前にブラウザによって呼び出される。
44 // (詳細はxm_player.html内のmoduleDidLoad()関数を見ること。)
45 // JavaScript関数のがpp::Varがたのmethodパラメータとして渡される。
46 // もしHasMethod()がtrueを返した場合、ブラウザはメソッドを実行するためにCall()メソッドを呼び出す。
47 class XmPlayerScriptableObject : public pp::deprecated::ScriptableObject {
48  public:
49   explicit XmPlayerScriptableObject(XmPlayerInstance& player)
50       : pp::deprecated::ScriptableObject(), player_(player) {}
51  
52   // ブラウザからmethod変数に格納されたメソッド名のメソッドが存在するか問い合わせる。
53   virtual bool HasMethod(const pp::Var& method, pp::Var* exception);
54   // ブラウザからproperty変数に格納されたプロパティ名のプロパティが存在するか問い合わせる。
55   virtual bool HasProperty(const pp::Var& property, pp::Var* exception);
56
57   // メソッドが実際に実行される場合に呼び出される。JavaScript側の引数はargsに格納される。
58   virtual pp::Var Call(const pp::Var& method,
59                        const std::vector<pp::Var>& args,
60                        pp::Var* exception);
61   // プロパティに値をセットする。
62   virtual void SetProperty(const pp::Var& property,
63                            const pp::Var& value,
64                            pp::Var* exception);
65   // プロパティ値に値を返す。
66   virtual pp::Var GetProperty(const pp::Var& property,
67                            pp::Var* exception);
68
69   private:
70   //  XM ファイルをロードする
71   bool LoadXmFile(const std::string& url);
72   // 再生する
73   bool PlaySound();
74   // 停止する
75   bool StopSound();
76   
77   XmPlayerInstance&  player_;
78   //pp::Audio* const audio_;  // weak
79   //double frequency_;
80 };
81
82 // The Instance class.  One of these exists for each instance of your NaCl
83 // module on the web page.  The browser will ask the Module object to create
84 // a new Instance for each occurence of the <embed> tag that has these
85 // attributes:
86 //     type="application/x-nacl"
87 //     nacl="xm_player.nmf"
88 //
89 // The Instance can return a ScriptableObject representing itself.  When the
90 // browser encounters JavaScript that wants to access the Instance, it calls
91 // the GetInstanceObject() method.  All the scripting work is done though
92 // the returned ScriptableObject.
93 class XmPlayerInstance : public pp::Instance {
94  public:
95   explicit XmPlayerInstance(PP_Instance instance)
96       : pp::Instance(instance), scriptable_object_(NULL),
97         sample_frame_count_(kSampleFrameCount)  , mod_( MOD__Create()){}
98   virtual ~XmPlayerInstance() 
99   {
100     MOD__Destruct(mod_);
101   }
102
103   // The pp::Var takes over ownership of the XmPlayerScriptableObject.
104   virtual pp::Var GetInstanceObject() {
105     scriptable_object_ =
106         new XmPlayerScriptableObject(*this);
107     return pp::Var(this, scriptable_object_);
108   }
109
110   virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
111
112     // Ask the device for an appropriate sample count size.
113     sample_frame_count_ =
114         pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
115                                                    kSampleFrameCount);
116     audio_ = pp::Audio(
117         this,
118         pp::AudioConfig(this,
119                         PP_AUDIOSAMPLERATE_44100,
120                         sample_frame_count_),
121         XmPlayerCallback, this);
122     return true;
123   }
124
125   void play()
126   {
127       if(MOD__LoadSong(mod_,&(load_data_[0]),load_data_.size()) > 0 ){
128           MOD__InitPlay(mod_);
129           audio_.StartPlayback();
130           pp::Var window = this->GetWindowObject();
131           // calls JavaScript function reportResult(url, result, success)
132           // defined in geturl.html.
133           pp::Var exception;
134           window.Call("reportResult", std::string("play()"), std::string("Play Start!!"), true, &exception);
135       } else {
136         pp::Var window = this->GetWindowObject();
137         // calls JavaScript function reportResult(url, result, success)
138         // defined in geturl.html.
139         pp::Var exception;
140         window.Call("reportResult", std::string("play()"), std::string("Load Error"), false, &exception);
141       };
142   }
143   void stop()
144   {
145     audio_.StopPlayback();
146   }
147   std::vector<char> & GetLoadData(){return load_data_;}
148
149  private:
150   static void XmPlayerCallback(void* samples, size_t buffer_size, void* data) {
151     XmPlayerInstance* xm_player_instance =
152         reinterpret_cast<XmPlayerInstance*>(data);
153     //int16_t* buff = reinterpret_cast<int16_t*>(samples);
154
155     // Make sure we can't write outside the buffer.
156     //assert(buffer_size >= (sizeof(*buff) * kChannels *
157     //                       xm_player_instance->sample_frame_count_));
158     MOD__PlaySong(xm_player_instance->mod_,reinterpret_cast<U32*>(samples),buffer_size / (sizeof(U32)));
159   }
160   // Audio resource. Allocated in Init()
161   pp::Audio audio_;
162
163   XmPlayerScriptableObject* scriptable_object_;
164
165   // The count of sample frames per channel in an audio buffer.
166   uint32_t sample_frame_count_;
167  // MOD構造体へのポインタ
168   ::MOD * mod_;
169   std::vector<char> load_data_;
170 };
171
172 // The Module class.  The browser calls the CreateInstance() method to create
173 // an instance of you NaCl module on the web page.  The browser creates a new
174 // instance for each <embed> tag with type="application/x-ppapi-nacl-srpc".
175 class XmPlayerModule : public pp::Module {
176  public:
177   XmPlayerModule() : pp::Module() {}
178   ~XmPlayerModule() {}
179
180   // Create and return a HelloWorldInstance object.
181   virtual pp::Instance* CreateInstance(PP_Instance instance) {
182     return new XmPlayerInstance(instance);
183   }
184 };
185
186 pp::Var XmPlayerScriptableObject::Call(const pp::Var& method,
187                                         const std::vector<pp::Var>& args,
188                                         pp::Var* exception) {
189   if (!method.is_string()) {
190     return pp::Var();
191   }
192   const std::string method_name = method.AsString();
193   if (method_name == kPlaySoundId) {
194     return pp::Var(PlaySound());
195   } else if (method_name == kStopSoundId) {
196     return pp::Var(StopSound());
197   } else if(method_name ==  kLoadXmFile ){
198    if ((args.size() >= 1) && args[0].is_string()) {
199       std::string url = args[0].AsString();
200       printf("GetURLScriptableObject::Call('%s'', '%s'')\n",
201              method_name.c_str(),
202              url.c_str());
203       fflush(stdout);
204     return pp::Var(LoadXmFile(url));
205    } else {
206      *exception = std::string("") + method_name;
207    }
208   } else {
209     *exception = std::string("No method named ") + method_name;
210   }
211   return pp::Var();
212 }
213
214 bool XmPlayerScriptableObject::HasMethod(const pp::Var& method,
215                                           pp::Var* exception) {
216   if (!method.is_string()) {
217     return false;
218   }
219   const std::string method_name = method.AsString();
220   const bool has_method = method_name == kPlaySoundId ||
221       method_name == kStopSoundId || method_name == kLoadXmFile;
222   return has_method;
223 }
224
225 bool XmPlayerScriptableObject::HasProperty(const pp::Var& property,
226                                             pp::Var* exception) {
227   return false;
228   //                                            if (!property.is_string()) {
229   //  return false;
230   //}
231   //const std::string property_name = property.AsString();
232   //const bool has_property = (property_name == kFrequencyId);
233   //return has_property;
234 }
235
236 void XmPlayerScriptableObject::SetProperty(const pp::Var& property,
237                                             const pp::Var& value,
238                                             pp::Var* exception) {
239   if (!property.is_string()) {
240     *exception = "Expected a property name of string type.";
241     return;
242   }
243   std::string property_name = property.AsString();
244   //if (property_name == kFrequencyId) {
245   //  // The value could come to us as an int32_t or a double, so we use pp::Var's
246   //  // is_number function which returns true when it's either kind of number.
247   //  if (value.is_number()) {
248   //    // And we get the value as an int32_t, and pp::Var does the conversion for
249   //    // us, if one is necessary.
250   //    set_frequency(value.AsDouble());
251   //    return;
252   //  } else if (value.is_string()) {
253   //    // We got the value as a string.  We'll try to convert it to a number.
254   //    std::istringstream stream(value.AsString());
255   //    double double_value;
256   //    if (stream >> double_value) {
257   //      set_frequency(double_value);
258   //      return;
259   //    } else {
260   //      std::string error_msg("Expected a number value for ");
261   //      error_msg += kFrequencyId;
262   //      error_msg += ".  Instead, got a non-numeric string: ";
263   //      error_msg += value.AsString();
264   //      *exception = error_msg;
265   //      return;
266   //    }
267   //    *exception = std::string("Expected a number value for ") + kFrequencyId;
268   //    return;
269   //  }
270   //}
271   *exception = std::string("No property named ") + property_name;
272 }
273
274 pp::Var XmPlayerScriptableObject::GetProperty(const pp::Var& property,
275                                                pp::Var* exception) {
276   if (!property.is_string()) {
277     *exception = "Expected a property name of string type.";
278     return pp::Var();
279   }
280   std::string property_name = property.AsString();
281   //if (property_name == kFrequencyId) {
282   //  return pp::Var(frequency());
283   //}
284   *exception = std::string("No property named ") + property_name;
285   return pp::Var();
286 }
287
288   bool XmPlayerScriptableObject::PlaySound() {
289     player_.play();
290     return true;
291   }
292   
293   bool XmPlayerScriptableObject::StopSound() {
294     player_.stop();
295     return true;
296   }
297
298   bool XmPlayerScriptableObject::LoadXmFile(const std::string& url)
299   {
300     //MODファイルのロード
301    GetURLHandler* handler_(GetURLHandler::Create(&player_,url,player_.GetLoadData()));
302    if(handler_)
303    {
304      if(!handler_->Start()){
305        return false;
306      };
307    } else {
308      return false;
309    }
310    return true;
311   }
312 }  // namespace xm_player
313
314 // Factory function called by the browser when the module is first loaded.
315 // The browser keeps a singleton of this module.  It calls the
316 // CreateInstance() method on the object you return to make instances.  There
317 // is one instance per <embed> tag on the page.  This is the main binding
318 // point for your NaCl module with the browser.
319 namespace pp {
320 Module* CreateModule() {
321   return new xm_player::XmPlayerModule();
322 }
323 }  // namespace pp