2 ==============================================================================
4 This file is part of the async
5 Copyright 2005-10 by Satoshi Fujiwara.
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.
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.
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
21 ==============================================================================
27 #define _CRTDBG_MAP_ALLOC
29 #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
32 #include "message_loop.h"
34 #include "application.h"
36 #include "async_reader.h"
38 #ifndef HINST_THISCOMPONENT
39 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
40 #define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
48 std::wstring application::app_id_(L"SF.async_debug");
50 std::wstring application::app_id_(L"SF.async");
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)
58 instance_handle_ = HINST_THISCOMPONENT;
59 status_.store(player_stop);
62 application::~application()
64 change_status(player_exit,boost::memory_order_release);
66 if(output_thread_.joinable())
68 output_thread_.join();
71 if(reader_thread_.joinable())
73 reader_thread_.join();
77 int application::execute(HINSTANCE hInstance,
78 HINSTANCE hPrevInstance,
83 ::_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
85 UNREFERENCED_PARAMETER(hPrevInstance);
86 UNREFERENCED_PARAMETER(lpCmdLine);
87 std::wcout.imbue(std::locale(""));
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;
98 sf::handle_holder handle(::CreateMutex(&sec_attr, FALSE, _T("async_mutex_debug")));
100 sf::handle_holder handle(::CreateMutex(&sec_attr, FALSE, _T("async_mutex")));
103 if(NULL == handle.get() || ::GetLastError() == ERROR_ALREADY_EXISTS)
109 static const INITCOMMONCONTROLSEX common_ctrls =
111 sizeof(INITCOMMONCONTROLSEX),
112 ICC_STANDARD_CLASSES | ICC_BAR_CLASSES
115 InitCommonControlsEx(&common_ctrls);
118 sf::com_initialize init();
121 sf::throw_if_err<application::exception>()(SetCurrentProcessExplicitAppUserModelID(app_id_.c_str()));
125 window_ = sf::create_toplevel_window(
126 std::wstring(L"async"),std::wstring(L"asyncテスト"));
129 reader_thread_ = boost::thread(boost::bind(&application::reader_thread_main,this));
131 output_thread_ = boost::thread(boost::bind(&application::output_thread_main,this));
133 // bool a = ringbuffer_.is_lock_free();
134 // wdout << ( ? L"**** true ****":L"---- false ----") << std::endl;
135 //sf::dialogbox(L"asyncテスト",L"asyncテスト");
137 // WPARAM ret = sf::run_message_loop()();
139 WPARAM ret = sf::dialog_message_loop(reinterpret_cast<HWND>(window_->raw_handle()))();
144 void application::set_play_position(uint64_t pos)
146 read_position_ = pos;
147 status_backup_ = status_.load();
148 change_status(player_seek);
151 void application::change_status(uint32_t v,boost::memory_order o)
154 SetEvent(event_output_.get());
155 SetEvent(event_reader_.get());
158 //void application::change_status_without_event(uint32_t v,boost::memory_order o)
160 // status_.store(v,o);
163 void application::reader_thread_main()
166 sf::com_initialize init();
170 WaitForSingleObject(event_reader_.get(),INFINITE);
171 switch(status_.load(boost::memory_order_acquire))
178 while(status_.load(boost::memory_order_acquire) == player_play)
180 if(reader_->more_data_available() || 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_)
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();
189 reader_->read_data(read_buffer_[read_index_].get(),sizeof(uint8_t) * size);
191 if(size < wasapi_->get_buffer_byte_size())
193 memset(read_buffer_[read_index_].get() + size,0,wasapi_->get_buffer_byte_size() - size);
197 not_enqueue_ = false;
198 while(!ringbuffer_.enqueue(read_buffer_[read_index_].get()))
200 if(status_.load() != player_play)
202 if(status_.load(boost::memory_order_relaxed) == player_pause)
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())
220 read_index_ = (++read_index_) & (read_buffer_.size() - 1);
224 status_.store(player_end);
232 wdout << boost::wformat(L"**Pause** index:%d address:%x") % read_index_ % read_buffer_[read_index_].get() << std::endl;
235 case player_prep_seek:
239 reader_->seek(read_position_);
241 output_counter_ = read_position_;
243 change_status(status_backup_);
245 case player_prep_stop:
248 reader_->reset_data_position();
251 change_status(player_ready);
255 // wdout << L"reader_threadは起動中" << std::endl;
259 wdout << L"##### reader_threadは終了!" << std::endl;
264 void application::output_thread_main()
268 sf::com_initialize init();
271 sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));
272 avmm.set_priority(AVRT_PRIORITY::AVRT_PRIORITY_CRITICAL);
277 WaitForSingleObject(event_output_.get(),INFINITE);
278 switch(status_.load(boost::memory_order_acquire))
285 // static BYTE *buffer_backup = 0;
287 // uint32_t buffer_count = 0;
288 while((status = status_.load(boost::memory_order_acquire)) == player_play)
290 if(ringbuffer_.dequeue(buffer))
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_)
300 output_counter_ -= reader_->total_data_bytes();
307 if(status == player_end)
309 while(ringbuffer_.dequeue(buffer))
311 wasapi_->play_buffer(buffer);
312 output_counter_ += wasapi_->get_buffer_byte_size();
322 case player_prep_seek:
324 change_status(player_seek);
328 case player_prep_stop:
330 change_status(player_stop);
339 wdout << L"***** output_threadは終了!" << std::endl;
344 void application::setup(const std::wstring& file_path)
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())
353 throw sf::win32_error_exception(*wasapi_->result());
357 for(int i = 0,size = read_buffer_.size();i < size;++i)
359 read_buffer_[i].reset(reinterpret_cast<uint8_t*>(_aligned_malloc(sizeof(uint8_t) * wasapi_->get_buffer_byte_size(),16)));
361 status_.store(player_ready);
363 } catch (sf::exception& e )
365 window_->message_box(wstring(L"エラーが発生しました。"),e.what_str());
369 void application::pause()
371 if(status_.load() == player_pause)
373 change_status(player_play);
376 change_status(player_pause);
381 void application::play()
383 change_status(player_play);
387 void application::stop()
389 change_status(player_prep_stop);
393 uint32_t application::get_status(boost::memory_order o)
395 return status_.load(o);