OSDN Git Service

キャプチャ部分のバグ修正。
[winaudioj/wasapi2.git] / wasapi2 / output_agent.cpp
1 /*\r
2 ==============================================================================\r
3 \r
4 This file is part of the async\r
5 Copyright 2005-10 by Satoshi Fujiwara.\r
6 \r
7 async can be redistributed and/or modified under the terms of the\r
8 GNU General Public License, as published by the Free Software Foundation;\r
9 either version 2 of the License, or (at your option) any later version.\r
10 \r
11 async is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 GNU General Public License for more details.\r
15 \r
16 You should have received a copy of the GNU General Public License\r
17 along with async; if not, visit www.gnu.org/licenses or write to the\r
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, \r
19 Boston, MA 02111-1307 USA\r
20 \r
21 ==============================================================================\r
22 */\r
23 #include "StdAfx.h"\r
24 #include <commctrl.h>\r
25 \r
26 #if _DEBUG\r
27 #define _CRTDBG_MAP_ALLOC\r
28 #include <crtdbg.h>\r
29 #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)\r
30 #endif\r
31 \r
32 #include "message_loop.h"\r
33 #include "sf_com.h"\r
34 #include "application.h"\r
35 #include "dout.h"\r
36 #include "async_reader.h"\r
37 #include "output_agent.h"\r
38 \r
39 \r
40 using namespace std;\r
41 using namespace boost;\r
42 \r
43 namespace sf {\r
44 \r
45   /// WASAPI出力スレッド\r
46   void output_agent_t::run()\r
47   {\r
48     // COMの初期化\r
49     sf::com_initialize init(0,multi_threaded);\r
50 \r
51     // MMCSSの初期化\r
52     sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));\r
53     avmm.set_priority(AVRT_PRIORITY_HIGH);\r
54     //apply_config_(\r
55     //  wasapi_device_manager::instance()->current_output_device_index(),\r
56     //  wasapi_device_manager::instance()->current_output_device().params);\r
57     BYTE* reader_buffer,*input_buffer,*mix_buffer;\r
58     uint32_t status;\r
59     size_t size_of_buffer = 0;\r
60     size_t remaining_of_buffer =  0;\r
61     BYTE* wasapi_buffer = 0;\r
62     size_t remaining_of_wasapi_buffer = 0;\r
63     memory_block_t mix_work;\r
64 \r
65     bool wasapi_ready = false;\r
66 \r
67     //if(wasapi_output_->is_enabled())\r
68     //{\r
69     //  change_status(status_processing);\r
70     //} else {\r
71       change_status(status_device_config);\r
72     //}\r
73 \r
74     application& app(*application::instance());\r
75 \r
76 \r
77     while(status = status_.load(std::memory_order_acquire), (status != status_exit ))\r
78     { \r
79       try {\r
80         switch (status)\r
81         {\r
82         case status_device_config:\r
83           // 出力デバイスの変更\r
84           if(wasapi_output_ && wasapi_output_->is_start())\r
85           {\r
86             wasapi_output_->stop();\r
87           }\r
88           remaining_of_buffer = 0;\r
89           change_status(status_device_config_ok);\r
90           break;\r
91         case status_process:\r
92           mix_work.reset(reinterpret_cast<BYTE*>(_aligned_malloc(sizeof(uint8_t) * wasapi_output_->get_buffer_byte_size(),16))); \r
93           change_status(status_processing);\r
94           // fall through\r
95         case status_processing:\r
96           {\r
97             size_of_buffer = wasapi_output_->get_buffer_size();\r
98             assert(wasapi_output_->is_enabled());\r
99             // 処理されたバイト数\r
100             if(remaining_of_buffer == 0) // データ残り0なら\r
101             {\r
102               //リングバッファから新たにデータを読み込む\r
103               //if(!app.mixer_ringbuffer().dequeue(reader_buffer)) // 読み込めない場合\r
104               int size = wasapi_output_->get_buffer_byte_size();\r
105               if(!app.reader_ringbuffer().dequeue(reader_buffer)) reader_buffer = 0;\r
106               if(!app.input_ringbuffer().dequeue(input_buffer)) input_buffer = 0;\r
107               if(input_buffer != 0 && reader_buffer != 0)\r
108               {\r
109                 ::CopyMemory(mix_work.get(),input_buffer,size);\r
110                 size = size / app.output_device().get_frame_size();\r
111                 WORD *destw((WORD*)mix_work.get()),*srcw((WORD*)reader_buffer);\r
112                 for(int i = 0;i < size;++i)\r
113                 {\r
114                   *destw++ += *srcw++;\r
115                   *destw++ += *srcw++;\r
116                 }\r
117               } else if(input_buffer != 0)\r
118               {\r
119                 ::CopyMemory(mix_work.get(),input_buffer,size);\r
120               } else if(reader_buffer != 0)\r
121               {\r
122                 ::CopyMemory(mix_work.get(),reader_buffer,size);\r
123               } else {\r
124                 get_buffer g(*wasapi_output_.get(),size_of_buffer);\r
125                                 if(g.size() != 0){\r
126                                         ::ZeroMemory(g.get(),g.size_byte());\r
127                                 }\r
128                 goto copy_end;\r
129               }\r
130               mix_buffer = mix_work.get();\r
131               remaining_of_buffer = size_of_buffer;\r
132             }\r
133 \r
134             // WASAPIからバッファアドレスを取得する\r
135             { get_buffer g(*wasapi_output_.get(),size_of_buffer);\r
136             wasapi_buffer = g;\r
137             remaining_of_wasapi_buffer = g.size();// バッファのサイズ必ずしも\r
138             // 要求したバイトが取得できるとはかぎらない\r
139 \r
140             if(remaining_of_buffer == remaining_of_wasapi_buffer)\r
141             {\r
142               // バッファの残りとWASAPIバッファの残りが同じとき\r
143               const uint32_t size_copy(remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
144               ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
145               remaining_of_buffer = 0;\r
146               remaining_of_wasapi_buffer = 0; \r
147             } else if(remaining_of_buffer > remaining_of_wasapi_buffer)\r
148             {\r
149               // バッファの残り>WASAPIバッファの残り\r
150               const uint32_t size_copy(remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
151               ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
152               mix_buffer += size_copy;\r
153               remaining_of_buffer -= remaining_of_wasapi_buffer;\r
154               remaining_of_wasapi_buffer = 0;\r
155             } else if(remaining_of_buffer < remaining_of_wasapi_buffer)\r
156             {\r
157               // バッファの残り<WASAPIバッファの残り\r
158               const uint32_t size_copy(remaining_of_buffer * wasapi_output_->get_frame_size());\r
159               ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
160               wasapi_buffer +=  size_copy;\r
161               remaining_of_wasapi_buffer -= remaining_of_buffer;\r
162 \r
163               int size = wasapi_output_->get_buffer_byte_size();\r
164               if(!app.reader_ringbuffer().dequeue(reader_buffer)) reader_buffer = 0;\r
165               if(!app.output_ringbuffer().dequeue(input_buffer)) input_buffer = 0;\r
166 \r
167               if(input_buffer != 0 && reader_buffer != 0)\r
168               {\r
169                 ::CopyMemory(mix_work.get(),input_buffer,size_of_buffer);\r
170                 size = size_of_buffer / app.output_device().get_frame_size();\r
171                 WORD *destw((WORD*)mix_work.get()),*srcw((WORD*)reader_buffer);\r
172                 for(int i = 0;i < size;++i)\r
173                 {\r
174                   *destw++ += *srcw++;\r
175                   *destw++ += *srcw++;\r
176                 }\r
177               } else if(input_buffer != 0)\r
178               {\r
179                 ::CopyMemory(mix_work.get(),input_buffer,size);\r
180               } else if(reader_buffer != 0)\r
181               {\r
182                 ::CopyMemory(mix_work.get(),reader_buffer,size);\r
183               } else {\r
184                 memset(wasapi_buffer,0,remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
185                 continue;\r
186               }\r
187               mix_buffer = mix_work.get();\r
188               {\r
189                 const uint32_t size_copy(remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());\r
190                 ::CopyMemory(wasapi_buffer,mix_buffer,size_copy);\r
191                 mix_buffer += size_copy;\r
192                 remaining_of_buffer = size_of_buffer - remaining_of_wasapi_buffer;\r
193               }\r
194             }\r
195             }\r
196 copy_end:\r
197             if(!wasapi_output_->is_start())\r
198             {\r
199               wasapi_output_->start();\r
200             }\r
201 \r
202             if(wasapi_output_->get_current_padding() == size_of_buffer)\r
203             {\r
204               wasapi_output_->wait();\r
205             } else {\r
206               DOUT(L"XXXX No Wait !!!! XXXX" << std::endl);\r
207             }\r
208           }\r
209           break;\r
210         default:\r
211         wait_event();\r
212 //        WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT);\r
213           break;\r
214         }\r
215       } catch (win32_error_exception& e) {\r
216         error_ = (wformat(L"出力スレッドでエラーが発生しました。:%s %x") % e.error() % e.hresult()).str();\r
217         change_status(status_error);\r
218       } catch (...) {\r
219         error_ = L"出力スレッドで不明なエラーが発生しました。";\r
220         change_status(status_error);\r
221       }\r
222     }\r
223 loop_end:\r
224     if(wasapi_output_){\r
225       if(wasapi_output_->is_start())\r
226       {\r
227         wasapi_output_->stop();\r
228       }\r
229       wasapi_output_.reset();\r
230     }\r
231     DOUT(L"***** output_threadは終了!" << std::endl);\r
232     agent::done();\r
233   };\r
234 \r
235   void output_agent_t::apply_config(int device_index,wasapi_device_manager::device_info::params_t& params)\r
236   {\r
237     if(status() != status_device_config_ok){ \r
238       change_and_wait(status_device_config,status_device_config_ok);\r
239     }\r
240 \r
241     apply_config_(device_index,params);\r
242 \r
243     change_and_wait(status_process,status_processing);\r
244 \r
245     //if(reader_ && status_.load() == reader_ready){\r
246     //  reader_->reset_data_position();\r
247     //  reader_index_ = 0;\r
248     //}\r
249   }\r
250 \r
251   void output_agent_t::apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params)\r
252   {\r
253 \r
254     //  assert(status_.load() == reader_stop);\r
255 \r
256     // 出力スレッドを設定変更状態にする\r
257 \r
258     WAVEFORMATEXTENSIBLE form;\r
259 \r
260     if(wasapi_output_)\r
261     {\r
262       if(wasapi_output_->is_start())\r
263       {\r
264         wasapi_output_->stop();\r
265       }\r
266       wasapi_output_.reset();\r
267     };\r
268 \r
269     try {\r
270       if(params.exclusive_mode)\r
271       {\r
272         if(params.event_mode){\r
273           wasapi_output_.reset(new sf::wasapi_exclusive_event(device_index,params));\r
274         } else {\r
275           wasapi_output_.reset(new sf::wasapi_exclusive_timer(device_index,params));\r
276         };\r
277       } else {\r
278         if(params.event_mode)\r
279         {\r
280           wasapi_output_.reset(new sf::wasapi_shared_event(device_index,params));\r
281         } else {\r
282           wasapi_output_.reset(new sf::wasapi_shared_timer(device_index,params));\r
283         }\r
284       }\r
285     } catch (win32_error_exception& e)\r
286     {\r
287 \r
288       //window_->message_box((boost::wformat(L"WASAPI初期化エラーが発生しました。設定パラメータを見なおしてください。%s") % e.error()).str(),wstring(L"WASAPI初期化エラー"));\r
289       throw;\r
290     }\r
291 \r
292     wasapi_device_manager::instance()->select_output_device(device_index);\r
293     wasapi_device_manager::instance()->current_output_device().params = params;\r
294 \r
295     // バッファのアロケート\r
296     init_buffer();\r
297 \r
298 \r
299   }\r
300 }\r
301 \r