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.
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>
22 #include "geturl_handler.h"
23 #include "boost/shared_ptr.hpp"
24 #include "boost/format.hpp"
28 const char* const kLoadXmFile = "loadXmFile";
30 const char* const kPlaySoundId = "playSound";
32 const char* const kStopSoundId = "stopSound";
34 // システムにリクエストするサンプルカウント数
35 const uint32_t kSampleFrameCount = 4096u;
36 // 現在サポートしているのはステレオオーディオのみである。
37 const uint32_t kChannels = 2u;
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 {
49 explicit XmPlayerScriptableObject(XmPlayerInstance& player)
50 : pp::deprecated::ScriptableObject(), player_(player) {}
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);
57 // メソッドが実際に実行される場合に呼び出される。JavaScript側の引数はargsに格納される。
58 virtual pp::Var Call(const pp::Var& method,
59 const std::vector<pp::Var>& args,
62 virtual void SetProperty(const pp::Var& property,
66 virtual pp::Var GetProperty(const pp::Var& property,
71 bool LoadXmFile(const std::string& url);
77 XmPlayerInstance& player_;
78 //pp::Audio* const audio_; // weak
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
86 // type="application/x-nacl"
87 // nacl="xm_player.nmf"
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 {
95 explicit XmPlayerInstance(PP_Instance instance)
96 : pp::Instance(instance), scriptable_object_(NULL),
97 sample_frame_count_(kSampleFrameCount) , mod_( MOD__Create()){}
98 virtual ~XmPlayerInstance()
103 // The pp::Var takes over ownership of the XmPlayerScriptableObject.
104 virtual pp::Var GetInstanceObject() {
106 new XmPlayerScriptableObject(*this);
107 return pp::Var(this, scriptable_object_);
110 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
112 // Ask the device for an appropriate sample count size.
113 sample_frame_count_ =
114 pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100,
118 pp::AudioConfig(this,
119 PP_AUDIOSAMPLERATE_44100,
120 sample_frame_count_),
121 XmPlayerCallback, this);
127 if(MOD__LoadSong(mod_,&(load_data_[0]),load_data_.size()) > 0 ){
129 audio_.StartPlayback();
130 pp::Var window = this->GetWindowObject();
131 // calls JavaScript function reportResult(url, result, success)
132 // defined in geturl.html.
134 window.Call("reportResult", std::string("play()"), std::string("Play Start!!"), true, &exception);
136 pp::Var window = this->GetWindowObject();
137 // calls JavaScript function reportResult(url, result, success)
138 // defined in geturl.html.
140 window.Call("reportResult", std::string("play()"), std::string("Load Error"), false, &exception);
145 audio_.StopPlayback();
147 std::vector<char> & GetLoadData(){return load_data_;}
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);
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)));
160 // Audio resource. Allocated in Init()
163 XmPlayerScriptableObject* scriptable_object_;
165 // The count of sample frames per channel in an audio buffer.
166 uint32_t sample_frame_count_;
169 std::vector<char> load_data_;
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 {
177 XmPlayerModule() : pp::Module() {}
180 // Create and return a HelloWorldInstance object.
181 virtual pp::Instance* CreateInstance(PP_Instance instance) {
182 return new XmPlayerInstance(instance);
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()) {
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",
204 return pp::Var(LoadXmFile(url));
206 *exception = std::string("") + method_name;
209 *exception = std::string("No method named ") + method_name;
214 bool XmPlayerScriptableObject::HasMethod(const pp::Var& method,
215 pp::Var* exception) {
216 if (!method.is_string()) {
219 const std::string method_name = method.AsString();
220 const bool has_method = method_name == kPlaySoundId ||
221 method_name == kStopSoundId || method_name == kLoadXmFile;
225 bool XmPlayerScriptableObject::HasProperty(const pp::Var& property,
226 pp::Var* exception) {
228 // if (!property.is_string()) {
231 //const std::string property_name = property.AsString();
232 //const bool has_property = (property_name == kFrequencyId);
233 //return has_property;
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.";
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());
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);
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;
267 // *exception = std::string("Expected a number value for ") + kFrequencyId;
271 *exception = std::string("No property named ") + property_name;
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.";
280 std::string property_name = property.AsString();
281 //if (property_name == kFrequencyId) {
282 // return pp::Var(frequency());
284 *exception = std::string("No property named ") + property_name;
288 bool XmPlayerScriptableObject::PlaySound() {
293 bool XmPlayerScriptableObject::StopSound() {
298 bool XmPlayerScriptableObject::LoadXmFile(const std::string& url)
301 GetURLHandler* handler_(GetURLHandler::Create(&player_,url,player_.GetLoadData()));
304 if(!handler_->Start()){
312 } // namespace xm_player
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.
320 Module* CreateModule() {
321 return new xm_player::XmPlayerModule();