OSDN Git Service

c2d0016e680b2fb7a88d1bde686916ae045dc5f8
[winaudioj/async.git] / async / application.cpp
1 /*
2   ==============================================================================
3
4    This file is part of the async
5    Copyright 2005-10 by Satoshi Fujiwara.
6
7    async can be redistributed and/or modified under the terms of the
8    GNU General Public License, as published by the Free Software Foundation;
9    either version 2 of the License, or (at your option) any later version.
10
11    async is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with async; if not, visit www.gnu.org/licenses or write to the
18    Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
19    Boston, MA 02111-1307 USA
20
21   ==============================================================================
22 */
23 #include "StdAfx.h"
24 #include <commctrl.h>
25
26 #if _DEBUG
27 #define _CRTDBG_MAP_ALLOC
28 #include <crtdbg.h>
29 #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
30 #endif
31
32 #include "message_loop.h"
33 #include "sf_com.h"
34 #include "application.h"
35 #include "dout.h"
36 #include "async_reader.h"
37
38 #ifndef HINST_THISCOMPONENT
39 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
40 #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
41 #endif
42
43
44 using namespace std;
45
46 namespace sf {
47 #ifdef _DEBUG
48   std::wstring application::app_id_(L"SF.async_debug");
49 #else
50   std::wstring application::app_id_(L"SF.async");
51 #endif
52
53   application::application() : 
54     event_output_(::CreateEventEx(NULL, NULL, 0, EVENT_MODIFY_STATE | SYNCHRONIZE)),
55     event_reader_(::CreateEventEx(NULL, NULL, 0, EVENT_MODIFY_STATE | SYNCHRONIZE)),
56     not_enqueue_(false),output_counter_(0),repeat_mode_(false)
57   {
58     instance_handle_ = HINST_THISCOMPONENT;
59     status_.store(player_stop);
60   }
61
62   application::~application()
63   {
64       change_status(player_exit,boost::memory_order_release);
65
66       if(output_thread_.joinable())
67       {
68         output_thread_.join();
69       }
70
71       if(reader_thread_.joinable())
72       {
73         reader_thread_.join();
74       }
75   };
76
77   int application::execute(HINSTANCE hInstance,
78     HINSTANCE hPrevInstance,
79     LPTSTR    lpCmdLine,
80     int       nCmdShow)
81   {
82 #ifdef _DEBUG
83     ::_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
84 #endif
85     UNREFERENCED_PARAMETER(hPrevInstance);
86     UNREFERENCED_PARAMETER(lpCmdLine);
87     std::wcout.imbue(std::locale(""));
88
89     // 2重起動の防止
90     SECURITY_DESCRIPTOR sd;
91     InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
92     SetSecurityDescriptorDacl(&sd, TRUE, 0, FALSE);         
93     SECURITY_ATTRIBUTES sec_attr;
94     sec_attr.nLength = sizeof (sec_attr);
95     sec_attr.lpSecurityDescriptor = &sd;
96     sec_attr.bInheritHandle = TRUE; 
97 #ifdef _DEBUG 
98     sf::handle_holder handle(::CreateMutex(&sec_attr, FALSE, _T("async_mutex_debug")));
99 #else
100     sf::handle_holder handle(::CreateMutex(&sec_attr, FALSE, _T("async_mutex")));
101 #endif
102
103     if(NULL == handle.get() || ::GetLastError() == ERROR_ALREADY_EXISTS)
104     {
105       return 0;
106     }
107
108     // コモンコントロールの初期化 
109     static const INITCOMMONCONTROLSEX common_ctrls =
110     {
111       sizeof(INITCOMMONCONTROLSEX),
112       ICC_STANDARD_CLASSES | ICC_BAR_CLASSES
113     };
114
115     InitCommonControlsEx(&common_ctrls);
116
117     // COMの初期化
118     sf::com_initialize init();
119
120     // アプリケーションIDの登録
121     sf::throw_if_err<application::exception>()(SetCurrentProcessExplicitAppUserModelID(app_id_.c_str()));
122     timeBeginPeriod(1);
123
124     // ウィンドウの作成
125     window_ = sf::create_toplevel_window(
126       std::wstring(L"async"),std::wstring(L"asyncテスト"));
127
128     // ファイルリーダースレッドの起動
129     reader_thread_ = boost::thread(boost::bind(&application::reader_thread_main,this));
130     // wasapi出力スレッドの起動
131     output_thread_ = boost::thread(boost::bind(&application::output_thread_main,this));
132
133  //   bool a = ringbuffer_.is_lock_free();
134 //    wdout << ( ? L"**** true ****":L"---- false ----") << std::endl;
135     //sf::dialogbox(L"asyncテスト",L"asyncテスト");
136     // メッセージループの実行
137     // WPARAM ret = sf::run_message_loop()();
138
139     WPARAM ret = sf::dialog_message_loop(reinterpret_cast<HWND>(window_->raw_handle()))();
140     timeEndPeriod(1);
141     return ret;
142   }
143
144   void application::set_play_position(uint64_t pos)
145   {
146     read_position_ = pos;
147     status_backup_ = status_.load();
148     change_status(player_seek);
149   }
150
151   void application::change_status(uint32_t v,boost::memory_order o)
152   {
153     status_.store(v,o);
154     SetEvent(event_output_.get());
155     SetEvent(event_reader_.get());
156   };
157
158   //void application::change_status_without_event(uint32_t v,boost::memory_order o)
159   //{
160   //  status_.store(v,o);
161   //};
162
163   void application::reader_thread_main()
164   {
165     // COMの初期化
166     sf::com_initialize init();
167     while(true)
168     {
169       // イベントを待つ
170       WaitForSingleObject(event_reader_.get(),INFINITE);
171       switch(status_.load(boost::memory_order_acquire))
172       {
173       case player_exit:
174         goto loop_end;
175         break;
176       case player_play:
177         {
178           while(status_.load(boost::memory_order_acquire) == player_play)
179           {
180             if(reader_->more_data_available() || not_enqueue_)
181             {
182               if(!not_enqueue_){              
183                 uint32_t size = reader_->data_bytes_remaining() >  wasapi_->get_buffer_byte_size() ?  wasapi_->get_buffer_byte_size() : reader_->data_bytes_remaining();
184                 if(size == 0 && repeat_mode_)
185                 {
186                   reader_->reset_data_position();
187                   size = reader_->data_bytes_remaining() >  wasapi_->get_buffer_byte_size() ?  wasapi_->get_buffer_byte_size() : reader_->data_bytes_remaining();
188                 }
189                 reader_->read_data(read_buffer_[read_index_].get(),sizeof(uint8_t) * size);
190                 reader_->wait();
191                 if(size < wasapi_->get_buffer_byte_size())
192                 {
193                   memset(read_buffer_[read_index_].get() + size,0,wasapi_->get_buffer_byte_size() - size);
194                 }
195               }
196
197               not_enqueue_ = false;
198               while(!ringbuffer_.enqueue(read_buffer_[read_index_].get()))
199               {
200                 if(status_.load() != player_play)
201                 {
202                   if(status_.load(boost::memory_order_relaxed) == player_pause)
203                   {
204                     not_enqueue_ = true;
205                   }
206                   break;
207                 } else {
208                   Sleep(1);
209                 }
210               }
211
212               ;
213 #ifdef _DEBUG
214               wdout << boost::wformat(L"index:%d address:%x 差分:%x") 
215                 % read_index_ % read_buffer_[read_index_].get()
216                 % (read_buffer_[(read_index_ + 1) & (read_buffer_.size() - 1)].get() - read_buffer_[read_index_].get())
217                 << std::endl;
218 #endif
219               if(!not_enqueue_){
220                 read_index_ = (++read_index_) & (read_buffer_.size() - 1);
221               }
222
223             } else {
224               status_.store(player_end);
225               break;
226             }
227           }
228         }
229         break;
230       case player_pause:
231 #ifdef _DEBUG
232         wdout << boost::wformat(L"**Pause** index:%d address:%x") % read_index_ % read_buffer_[read_index_].get() << std::endl;
233 #endif
234         break;
235       case player_prep_seek:
236
237         break;
238       case player_seek:
239         reader_->seek(read_position_);
240         ringbuffer_.reset();
241         output_counter_ = read_position_;
242         read_index_ = 0;
243         change_status(status_backup_);
244         break;
245       case player_prep_stop:
246         break;
247       case player_stop:
248         reader_->reset_data_position();
249         ringbuffer_.reset();
250         output_counter_ = 0;
251         change_status(player_ready);
252         break;
253       }
254       Sleep(1);
255 //      wdout << L"reader_threadは起動中" << std::endl;
256     }
257 loop_end:
258 #ifdef _DEBUG
259     wdout << L"##### reader_threadは終了!" << std::endl;
260 #endif
261   ;};
262
263   /// WASAPI出力スレッド
264   void application::output_thread_main()
265   {
266     {
267     // COMの初期化
268     sf::com_initialize init();
269
270     // MMCSSの初期化
271     sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));
272     avmm.set_priority(AVRT_PRIORITY::AVRT_PRIORITY_CRITICAL);
273
274     while(true)
275     { 
276       //イベントを待つ
277       WaitForSingleObject(event_output_.get(),INFINITE);
278       switch(status_.load(boost::memory_order_acquire))
279       {
280       case player_exit:
281         goto loop_end;
282         break;
283       case player_play:
284         {BYTE* buffer;
285 //        static BYTE *buffer_backup = 0;
286         uint32_t status;
287 //        uint32_t buffer_count = 0;
288         while((status = status_.load(boost::memory_order_acquire)) == player_play)
289         {
290           if(ringbuffer_.dequeue(buffer))
291           {
292             wasapi_->play_buffer(buffer);
293 //            sf::wdout << boost::wformat(L"play_buffer:%d address:%x") % (buffer_count) % buffer << std::endl;
294 //            sf::wdout << boost::wformat(L"差分:%x") % (buffer - buffer_backup) << std::endl;
295 //            buffer_backup = buffer;
296 //            buffer_count = (++buffer_count) & 0x7f;
297             output_counter_ += wasapi_->get_buffer_byte_size();
298             if(output_counter_ > reader_->total_data_bytes() && repeat_mode_)
299             {
300               output_counter_ -= reader_->total_data_bytes();
301             };
302           } else {
303             Sleep(0);
304           }
305         }
306
307         if(status == player_end)
308         {
309           while(ringbuffer_.dequeue(buffer))
310           {
311             wasapi_->play_buffer(buffer);
312             output_counter_ += wasapi_->get_buffer_byte_size();
313           }
314           stop();
315         }
316         }
317
318         break;
319       case player_pause:
320         wasapi_->stop();
321         break;
322       case player_prep_seek:
323         wasapi_->stop();
324         change_status(player_seek);
325         break;
326       case player_seek:
327         break;
328       case player_prep_stop:
329         wasapi_->stop();
330         change_status(player_stop);
331         break;
332       case player_stop:
333         break;
334       }
335       Sleep(0);
336     }
337 loop_end:
338 #ifdef _DEBUG
339     wdout << L"***** output_threadは終了!" << std::endl;
340 #endif
341     ;}
342 ;  };
343
344   void application::setup(const std::wstring& file_path)
345   {
346     try {
347       source_file_path_ = file_path;
348 //      reader_.reset(new wave_file_reader(file_path,false));
349       reader_.reset(new async_reader(file_path,false));
350       wasapi_.reset(new sf::wasapi_shared_timer(reader_->get_wave_format()));
351       if(!wasapi_->is_enabled())
352       {
353         throw sf::win32_error_exception(*wasapi_->result());
354       }
355       read_index_ = 0;
356       //
357       for(int i = 0,size = read_buffer_.size();i < size;++i)
358       {
359         read_buffer_[i].reset(reinterpret_cast<uint8_t*>(_aligned_malloc(sizeof(uint8_t) * wasapi_->get_buffer_byte_size(),16)));
360       }
361       status_.store(player_ready);
362       window_->ready();
363     } catch (sf::exception& e )
364     {
365       window_->message_box(wstring(L"エラーが発生しました。"),e.what_str());
366     }
367   };
368
369   void application::pause()
370   {
371     if(status_.load() == player_pause)
372     {
373       change_status(player_play);
374       window_->play();
375     } else {
376       change_status(player_pause);
377       window_->pause();
378     }
379   }
380
381   void application::play()
382   {
383     change_status(player_play);
384     window_->play();
385   }
386
387   void application::stop()
388   {
389     change_status(player_prep_stop);
390     window_->stop();
391   }
392
393   uint32_t application::get_status(boost::memory_order o)
394   {
395     return status_.load(o);
396   }
397 }
398