2 ==============================================================================
\r
4 This file is part of the async
\r
5 Copyright 2005-10 by Satoshi Fujiwara.
\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
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
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
21 ==============================================================================
\r
24 #include <commctrl.h>
\r
27 #define _CRTDBG_MAP_ALLOC
\r
29 #define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
\r
32 #include "message_loop.h"
\r
34 #include "application.h"
\r
36 #include "async_reader.h"
\r
37 #include "output_agent.h"
\r
40 using namespace std;
\r
41 using namespace boost;
\r
46 void output_agent_t::run()
\r
49 sf::com_initialize init(0,multi_threaded);
\r
52 sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio"));
\r
53 avmm.set_priority(AVRT_PRIORITY_HIGH);
\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
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
65 bool wasapi_ready = false;
\r
67 //if(wasapi_output_->is_enabled())
\r
69 // change_status(status_processing);
\r
71 change_status(status_device_config);
\r
74 application& app(*application::instance());
\r
77 while(status = status_.load(std::memory_order_acquire), (status != status_exit ))
\r
82 case status_device_config:
\r
84 if(wasapi_output_ && wasapi_output_->is_start())
\r
86 wasapi_output_->stop();
\r
88 remaining_of_buffer = 0;
\r
89 change_status(status_device_config_ok);
\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
95 case status_processing:
\r
97 size_of_buffer = wasapi_output_->get_buffer_size();
\r
98 assert(wasapi_output_->is_enabled());
\r
100 if(remaining_of_buffer == 0) // データ残り0なら
\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
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
114 *destw++ += *srcw++;
\r
115 *destw++ += *srcw++;
\r
117 } else if(input_buffer != 0)
\r
119 ::CopyMemory(mix_work.get(),input_buffer,size);
\r
120 } else if(reader_buffer != 0)
\r
122 ::CopyMemory(mix_work.get(),reader_buffer,size);
\r
124 get_buffer g(*wasapi_output_.get(),size_of_buffer);
\r
126 ::ZeroMemory(g.get(),g.size_byte());
\r
130 mix_buffer = mix_work.get();
\r
131 remaining_of_buffer = size_of_buffer;
\r
134 // WASAPIからバッファアドレスを取得する
\r
135 { get_buffer g(*wasapi_output_.get(),size_of_buffer);
\r
137 remaining_of_wasapi_buffer = g.size();// バッファのサイズ必ずしも
\r
138 // 要求したバイトが取得できるとはかぎらない
\r
140 if(remaining_of_buffer == remaining_of_wasapi_buffer)
\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
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
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
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
167 if(input_buffer != 0 && reader_buffer != 0)
\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
174 *destw++ += *srcw++;
\r
175 *destw++ += *srcw++;
\r
177 } else if(input_buffer != 0)
\r
179 ::CopyMemory(mix_work.get(),input_buffer,size);
\r
180 } else if(reader_buffer != 0)
\r
182 ::CopyMemory(mix_work.get(),reader_buffer,size);
\r
184 memset(wasapi_buffer,0,remaining_of_wasapi_buffer * wasapi_output_->get_frame_size());
\r
187 mix_buffer = mix_work.get();
\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
197 if(!wasapi_output_->is_start())
\r
199 wasapi_output_->start();
\r
202 if(wasapi_output_->get_current_padding() == size_of_buffer)
\r
204 wasapi_output_->wait();
\r
206 DOUT(L"XXXX No Wait !!!! XXXX" << std::endl);
\r
212 // WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT);
\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
219 error_ = L"出力スレッドで不明なエラーが発生しました。";
\r
220 change_status(status_error);
\r
224 if(wasapi_output_){
\r
225 if(wasapi_output_->is_start())
\r
227 wasapi_output_->stop();
\r
229 wasapi_output_.reset();
\r
231 DOUT(L"***** output_threadは終了!" << std::endl);
\r
235 void output_agent_t::apply_config(int device_index,wasapi_device_manager::device_info::params_t& params)
\r
237 if(status() != status_device_config_ok){
\r
238 change_and_wait(status_device_config,status_device_config_ok);
\r
241 apply_config_(device_index,params);
\r
243 change_and_wait(status_process,status_processing);
\r
245 //if(reader_ && status_.load() == reader_ready){
\r
246 // reader_->reset_data_position();
\r
247 // reader_index_ = 0;
\r
251 void output_agent_t::apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params)
\r
254 // assert(status_.load() == reader_stop);
\r
256 // 出力スレッドを設定変更状態にする
\r
258 WAVEFORMATEXTENSIBLE form;
\r
262 if(wasapi_output_->is_start())
\r
264 wasapi_output_->stop();
\r
266 wasapi_output_.reset();
\r
270 if(params.exclusive_mode)
\r
272 if(params.event_mode){
\r
273 wasapi_output_.reset(new sf::wasapi_exclusive_event(device_index,params));
\r
275 wasapi_output_.reset(new sf::wasapi_exclusive_timer(device_index,params));
\r
278 if(params.event_mode)
\r
280 wasapi_output_.reset(new sf::wasapi_shared_event(device_index,params));
\r
282 wasapi_output_.reset(new sf::wasapi_shared_timer(device_index,params));
\r
285 } catch (win32_error_exception& e)
\r
288 //window_->message_box((boost::wformat(L"WASAPI初期化エラーが発生しました。設定パラメータを見なおしてください。%s") % e.error()).str(),wstring(L"WASAPI初期化エラー"));
\r
292 wasapi_device_manager::instance()->select_output_device(device_index);
\r
293 wasapi_device_manager::instance()->current_output_device().params = params;
\r