wasapiを実験するプロジェクトです。
Revision | d312260236d979ba5136674b5cec3b81625f7d99 (tree) |
---|---|
Time | 2012-11-10 14:44:00 |
Author | sfpg <sfpg@user...> |
Commiter | sfpg |
Windows8上で動作するようにバグ修正。キャプチャ部分はまだ修正は完了していない。
@@ -3,10 +3,10 @@ | ||
3 | 3 | <ImportGroup Label="PropertySheets" /> |
4 | 4 | <PropertyGroup Label="UserMacros" /> |
5 | 5 | <PropertyGroup> |
6 | - <IncludePath>H:\libs\DirectXTK\Inc;H:\libs\boost_1_51_0\boost_1_51_0;H:\libs\xbyak\xbyak;H:\libs\zlib125\zlib-1.2.5;H:\libs\lpng150\lpng150;$(IncludePath)</IncludePath> | |
6 | + <IncludePath>H:\libs\DirectXTK\Inc;H:\libs\boost\include\boost-1_52;H:\libs\xbyak\xbyak;H:\libs\zlib125\zlib-1.2.5;H:\libs\lpng150\lpng150;$(IncludePath)</IncludePath> | |
7 | 7 | </PropertyGroup> |
8 | 8 | <PropertyGroup> |
9 | - <LibraryPath>H:\libs\zlib125\zlib-1.2.5;$(LibraryPath)</LibraryPath> | |
9 | + <LibraryPath>H:\libs\zlib125\zlib-1.2.5;H:\libs\boost\lib;$(LibraryPath)</LibraryPath> | |
10 | 10 | </PropertyGroup> |
11 | 11 | <ItemDefinitionGroup> |
12 | 12 | <ClCompile> |
@@ -94,7 +94,6 @@ namespace sf { | ||
94 | 94 | return 0; |
95 | 95 | } |
96 | 96 | |
97 | - // プロセスの優先順位 | |
98 | 97 | SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
99 | 98 | |
100 | 99 | // コモンコントロールの初期化 |
@@ -108,9 +107,15 @@ namespace sf { | ||
108 | 107 | |
109 | 108 | // COMの初期化 |
110 | 109 | sf::com_initialize init(0,multi_threaded); |
110 | + | |
111 | + // プロセスの優先順位 | |
112 | + sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio")); | |
113 | + avmm.set_priority(AVRT_PRIORITY_HIGH); | |
114 | + | |
111 | 115 | // アプリケーションIDの登録 |
112 | 116 | sf::throw_if_err<application::exception>()(SetCurrentProcessExplicitAppUserModelID(app_id_.c_str())); |
113 | 117 | timeBeginPeriod(1); |
118 | + sf::wasapi_device_manager::instance()->wait_enum_devices(); | |
114 | 119 | sf::wasapi_device_manager::instance()->current_output_device(); |
115 | 120 | |
116 | 121 | // ウィンドウの作成 |
@@ -119,10 +124,10 @@ namespace sf { | ||
119 | 124 | |
120 | 125 | |
121 | 126 | // bool a = reader_ringbuffer_.is_lock_free(); |
122 | - // wdout << ( ? L"**** true ****":L"---- false ----") << std::endl; | |
123 | - // mixer スレッドの起動 | |
124 | - //mixer_thread_.execute(); | |
125 | - // ファイルリーダースレッドの起動 | |
127 | + /// wdout << ( ? L"**** true ****":L"---- false ----") << std::endl; | |
128 | + // mixer スレッドの起動 | |
129 | + mixer_thread_.execute(); | |
130 | + // ファイルリーダースレッドの起動 | |
126 | 131 | reader_thread_.execute(); |
127 | 132 | |
128 | 133 | input_thread_.execute(); |
@@ -136,10 +141,10 @@ namespace sf { | ||
136 | 141 | output_thread_.wait_status(output_thread_t::status_device_config_ok); |
137 | 142 | apply_output_device_config |
138 | 143 | (wasapi_device_manager::instance()->current_output_device_index(), |
139 | - wasapi_device_manager::instance()->current_output_device().params); | |
144 | + wasapi_device_manager::instance()->current_output_device().params); | |
140 | 145 | apply_input_device_config |
141 | 146 | (wasapi_device_manager::instance()->current_input_device_index(), |
142 | - wasapi_device_manager::instance()->current_input_device().params); | |
147 | + wasapi_device_manager::instance()->current_input_device().params); | |
143 | 148 | } catch (...) { |
144 | 149 | |
145 | 150 | } |
@@ -150,16 +155,17 @@ namespace sf { | ||
150 | 155 | // スレッドを終了する |
151 | 156 | reader_thread_.change_status(reader_thread_t::status_exit); |
152 | 157 | input_thread_.change_status(input_thread_t::status_exit); |
153 | - // mixer_thread_.change_status(mixer_thread_t::status_exit); | |
158 | + mixer_thread_.change_status(mixer_thread_t::status_exit); | |
154 | 159 | output_thread_.change_status(output_thread_t::status_exit); |
155 | 160 | |
156 | - // スレッド終了待ち | |
157 | - //mixer_thread_.join(); | |
161 | + // スレッド終了待ち | |
162 | + mixer_thread_.join(); | |
158 | 163 | reader_thread_.join(); |
159 | 164 | output_thread_.join(); |
160 | 165 | input_thread_.join(); |
161 | - | |
166 | + | |
162 | 167 | // WASAPIをシャットダウンする |
168 | + wasapi_device_manager::instance()->save_params(); | |
163 | 169 | wasapi_device_manager::instance().reset(); |
164 | 170 | |
165 | 171 | return ret; |
@@ -169,8 +175,8 @@ namespace sf { | ||
169 | 175 | { |
170 | 176 | try { |
171 | 177 | reader_thread_.setup(file_path); |
172 | - window_->reader_ready(); | |
173 | - } catch (win32_error_exception& e) { | |
178 | + window_->reader_ready(); | |
179 | + } catch (win32_error_exception& e) { | |
174 | 180 | window_->message_box((boost::wformat(L"ファイル読み込み時にエラーが発生しました。%s") % e.error()).str(),wstring(L"ファイル読込エラー")); |
175 | 181 | } |
176 | 182 | } |
@@ -178,34 +184,34 @@ namespace sf { | ||
178 | 184 | void application::reader_read_file() |
179 | 185 | { |
180 | 186 | try { |
181 | - reader_thread_.read_file(); | |
182 | - window_->reader_read_file(); | |
183 | - } catch (win32_error_exception& e) { | |
187 | + reader_thread_.read_file(); | |
188 | + window_->reader_read_file(); | |
189 | + } catch (win32_error_exception& e) { | |
184 | 190 | window_->message_box((boost::wformat(L"再生開始時にエラーが発生しました。%s") % e.error()).str(),wstring(L"再生エラー")); |
185 | 191 | } |
186 | 192 | } |
187 | - | |
193 | + | |
188 | 194 | void application::reader_pause() |
189 | 195 | { |
190 | 196 | try { |
191 | - reader_thread_.pause(); | |
192 | - if(reader_thread_.status() == reader_thread_t::status_pause_ok) | |
193 | - { | |
194 | - window_->reader_pause(); | |
195 | - } else { | |
196 | - window_->reader_read_file(); | |
197 | - } | |
198 | - } catch (win32_error_exception& e) { | |
197 | + reader_thread_.pause(); | |
198 | + if(reader_thread_.status() == reader_thread_t::status_pause_ok) | |
199 | + { | |
200 | + window_->reader_pause(); | |
201 | + } else { | |
202 | + window_->reader_read_file(); | |
203 | + } | |
204 | + } catch (win32_error_exception& e) { | |
199 | 205 | window_->message_box((boost::wformat(L"一時停止時にエラーが発生しました。%s") % e.error()).str(),wstring(L"一時停止エラー")); |
200 | 206 | } |
201 | 207 | } |
202 | - | |
208 | + | |
203 | 209 | void application::reader_stop() |
204 | 210 | { |
205 | 211 | try { |
206 | - reader_thread_.stop(); | |
207 | - window_->reader_stop(); | |
208 | - } catch (win32_error_exception& e) { | |
212 | + reader_thread_.stop(); | |
213 | + window_->reader_stop(); | |
214 | + } catch (win32_error_exception& e) { | |
209 | 215 | window_->message_box((boost::wformat(L"停止時にエラーが発生しました。%s") % e.error()).str(),wstring(L"停止エラー")); |
210 | 216 | } |
211 | 217 | } |
@@ -221,8 +227,8 @@ namespace sf { | ||
221 | 227 | int reader_status = reader_thread_.status(); |
222 | 228 | reader_thread_.change_and_wait(reader_thread_t::status_config,reader_thread_t::status_config_ok); |
223 | 229 | |
224 | - // int mixer_status = mixer_thread_.status(); | |
225 | - // mixer_thread_.change_and_wait(mixer_thread_t::status_config,mixer_thread_t::status_config_ok); | |
230 | + // int mixer_status = mixer_thread_.status(); | |
231 | + // mixer_thread_.change_and_wait(mixer_thread_t::status_config,mixer_thread_t::status_config_ok); | |
226 | 232 | |
227 | 233 | int input_status = input_thread_.status(); |
228 | 234 | input_thread_.change_and_wait(input_thread_t::status_pause,input_thread_t::status_pause_ok); |
@@ -230,8 +236,8 @@ namespace sf { | ||
230 | 236 | // 出力の変更 |
231 | 237 | output_thread_.apply_config(device_index,params); |
232 | 238 | |
233 | - // mixer_thread_.init_buffer(); | |
234 | - // mixer_thread_.change_and_wait(mixer_thread_t::status_process,mixer_thread_t::status_processing); | |
239 | + // mixer_thread_.init_buffer(); | |
240 | + // mixer_thread_.change_and_wait(mixer_thread_t::status_process,mixer_thread_t::status_processing); | |
235 | 241 | |
236 | 242 | reader_thread_.init_buffer(); |
237 | 243 | reader_thread_.change_and_wait(reader_thread_t::status_ready,reader_thread_t::status_ready_ok); |
@@ -61,7 +61,9 @@ struct get_buffer | ||
61 | 61 | |
62 | 62 | ~get_buffer() |
63 | 63 | { |
64 | - audio_base_.release_buffer(buffer_size_); | |
64 | + if(buffer_ptr_ != nullptr && buffer_size_ != 0){ | |
65 | + audio_base_.release_buffer(buffer_size_); | |
66 | + } | |
65 | 67 | } |
66 | 68 | |
67 | 69 | operator BYTE*(){return buffer_ptr_;} |
@@ -40,167 +40,172 @@ using namespace std; | ||
40 | 40 | |
41 | 41 | namespace sf { |
42 | 42 | |
43 | -void input_thread_t::thread_main() | |
44 | -{ | |
45 | - // COMの初期化 | |
46 | - sf::com_initialize init(0,multi_threaded); | |
47 | - | |
48 | - // MMCSSの初期化 | |
49 | - sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio")); | |
50 | - avmm.set_priority(AVRT_PRIORITY_HIGH); | |
51 | - | |
52 | - //// input デバイスの初期化 | |
53 | - //wasapi_device_manager::ptr m(wasapi_device_manager::instance()); | |
54 | - //apply_config_( | |
55 | - // m->current_input_device_index(), | |
56 | - // m->current_input_device().params | |
57 | - //); | |
58 | - change_status(status_pause); | |
59 | - application& app(*application::instance()); | |
60 | - int status = STATUS_ERROR; | |
61 | - BYTE *buffer = 0; | |
62 | - index_ = 0; | |
63 | - int source_counter ,dest_counter; | |
64 | - source_counter = dest_counter = 0; | |
65 | - //// 出力デバイスが稼働するまで待つ | |
66 | - //app.output_thread().wait_status(output_thread_t::status_processing,10); | |
67 | - //apply_config_( | |
68 | - //wasapi_device_manager::instance()->current_input_device_index(), | |
69 | - //wasapi_device_manager::instance()->current_input_device().params); | |
70 | - change_status(status_device_config); | |
71 | - while(status = status_.load(),status != status_exit) | |
43 | + void input_thread_t::thread_main() | |
72 | 44 | { |
73 | - // イベントを待つ | |
74 | - switch(status) | |
45 | + // COMの初期化 | |
46 | + sf::com_initialize init(0,multi_threaded); | |
47 | + | |
48 | + // MMCSSの初期化 | |
49 | + sf::av_mm_thread_characteristics avmm(wstring(L"Pro Audio")); | |
50 | + avmm.set_priority(AVRT_PRIORITY_HIGH); | |
51 | + | |
52 | + //// input デバイスの初期化 | |
53 | + //wasapi_device_manager::ptr m(wasapi_device_manager::instance()); | |
54 | + //apply_config_( | |
55 | + // m->current_input_device_index(), | |
56 | + // m->current_input_device().params | |
57 | + //); | |
58 | + change_status(status_pause); | |
59 | + application& app(*application::instance()); | |
60 | + int status = STATUS_ERROR; | |
61 | + BYTE *buffer = 0; | |
62 | + index_ = 0; | |
63 | + int source_counter ,dest_counter; | |
64 | + source_counter = dest_counter = 0; | |
65 | + //// 出力デバイスが稼働するまで待つ | |
66 | + //app.output_thread().wait_status(output_thread_t::status_processing,10); | |
67 | + //apply_config_( | |
68 | + //wasapi_device_manager::instance()->current_input_device_index(), | |
69 | + //wasapi_device_manager::instance()->current_input_device().params); | |
70 | + change_status(status_device_config); | |
71 | + while(status = status_.load(),status != status_exit) | |
75 | 72 | { |
76 | - case status_device_config: | |
77 | - if(wasapi_input_) | |
73 | + // イベントを待つ | |
74 | + switch(status) | |
78 | 75 | { |
79 | - wasapi_input_->stop(); | |
80 | - dest_counter = 0; | |
81 | - } | |
82 | - change_status(status_device_config_ok); | |
83 | - break; | |
84 | - case status_process: | |
85 | - if(!wasapi_input_->is_start()){ | |
86 | - wasapi_input_->start(); | |
87 | - } | |
88 | - change_status(status_processing); | |
89 | - case status_processing: | |
90 | - { | |
91 | - wasapi_input_->wait();// 入力待ち | |
92 | - get_buffer g(*wasapi_input_);// キャプチャバッファの取得 | |
93 | - if(g.size() && g != 0) | |
76 | + case status_device_config: | |
77 | + if(wasapi_input_) | |
94 | 78 | { |
95 | - source_counter = 0; | |
96 | - while(source_counter != g.size()) | |
97 | - { | |
98 | - BYTE * src = g + source_counter * wasapi_input_->get_frame_size(); | |
99 | - int size_byte_src = g.size_byte() - source_counter * wasapi_input_->get_frame_size(); | |
100 | - int size_src = g.size() - source_counter; | |
101 | - | |
102 | - BYTE * dest = buffer_[index_].get() + dest_counter * app.output_device().get_frame_size(); | |
103 | - int size_byte_dest = app.output_device().get_buffer_byte_size() - dest_counter * app.output_device().get_frame_size(); | |
104 | - int size_dest = app.output_device().get_buffer_size() - dest_counter; | |
105 | - | |
106 | - if(size_src <= size_dest) | |
107 | - { | |
108 | - ::CopyMemory(dest,src,size_byte_src); | |
109 | - source_counter += size_src; | |
110 | - dest_counter += size_src; | |
111 | - } else if(size_src > size_dest) | |
112 | - { | |
113 | - ::CopyMemory(dest,src,size_byte_dest); | |
114 | - source_counter += size_dest; | |
115 | - dest_counter += size_dest; | |
116 | - } | |
117 | - if(dest_counter == app.output_device().get_buffer_size()) | |
118 | - { | |
119 | - if(ringbuffer_.enqueue(buffer_[index_].get())) | |
120 | - { | |
121 | - index_ = (index_ + 1) & (buffer_.size() - 1); | |
122 | - } | |
123 | - dest_counter = 0; | |
124 | - } | |
125 | - } | |
79 | + wasapi_input_->stop(); | |
80 | + dest_counter = 0; | |
126 | 81 | } |
82 | + change_status(status_device_config_ok); | |
83 | + break; | |
84 | + case status_process: | |
85 | + if(!wasapi_input_->is_start()){ | |
86 | + wasapi_input_->start(); | |
87 | + } | |
88 | + change_status(status_processing); | |
89 | + case status_processing: | |
90 | + { | |
91 | + wasapi_input_->wait();// 入力待ち | |
92 | + //try{ | |
93 | + // get_buffer g(*wasapi_input_);// キャプチャバッファの取得 | |
94 | + // if(g.size() && g != 0) | |
95 | + // { | |
96 | + // source_counter = 0; | |
97 | + // while(source_counter != g.size()) | |
98 | + // { | |
99 | + // BYTE * src = g + source_counter * wasapi_input_->get_frame_size(); | |
100 | + // int size_byte_src = g.size_byte() - source_counter * wasapi_input_->get_frame_size(); | |
101 | + // int size_src = g.size() - source_counter; | |
102 | + | |
103 | + // BYTE * dest = buffer_[index_].get() + dest_counter * app.output_device().get_frame_size(); | |
104 | + // int size_byte_dest = app.output_device().get_buffer_byte_size() - dest_counter * app.output_device().get_frame_size(); | |
105 | + // int size_dest = app.output_device().get_buffer_size() - dest_counter; | |
106 | + | |
107 | + // if(size_src <= size_dest) | |
108 | + // { | |
109 | + // ::CopyMemory(dest,src,size_byte_src); | |
110 | + // source_counter += size_src; | |
111 | + // dest_counter += size_src; | |
112 | + // } else if(size_src > size_dest) | |
113 | + // { | |
114 | + // ::CopyMemory(dest,src,size_byte_dest); | |
115 | + // source_counter += size_dest; | |
116 | + // dest_counter += size_dest; | |
117 | + // } | |
118 | + // if(dest_counter == app.output_device().get_buffer_size()) | |
119 | + // { | |
120 | + // if(ringbuffer_.enqueue(buffer_[index_].get())) | |
121 | + // { | |
122 | + // index_ = (index_ + 1) & (buffer_.size() - 1); | |
123 | + // } | |
124 | + // dest_counter = 0; | |
125 | + // } | |
126 | + // } | |
127 | + // } | |
128 | + //} catch (...) { | |
129 | + // ; | |
130 | + //} | |
131 | + } | |
132 | + | |
133 | + break; | |
134 | + case status_pause: | |
135 | + if(wasapi_input_) | |
136 | + { | |
137 | + wasapi_input_->stop(); | |
138 | + } | |
139 | + change_status(status_pause_ok); | |
140 | + break; | |
141 | + default: | |
142 | + WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT); | |
143 | + break; | |
127 | 144 | } |
128 | - break; | |
129 | - case status_pause: | |
130 | - if(wasapi_input_) | |
131 | - { | |
132 | - wasapi_input_->stop(); | |
133 | - } | |
134 | - change_status(status_pause_ok); | |
135 | - break; | |
136 | - default: | |
137 | - WaitForSingleObject(event_.get(),WAIT_TIMEOUT_DEFAULT); | |
138 | - break; | |
139 | 145 | } |
140 | - } | |
141 | 146 | loop_end: |
142 | - ; | |
143 | - DOUT(L"##### input_threadは終了!" << endl); | |
144 | - if(wasapi_input_ && wasapi_input_->is_start()) | |
145 | - { | |
146 | - wasapi_input_->stop(); | |
147 | - } | |
148 | - wasapi_input_.reset(); | |
149 | -}; | |
150 | - | |
151 | -void input_thread_t::apply_config(int device_index,wasapi_device_manager::device_info::params_t& params) | |
152 | -{ | |
153 | - if(status() != status_device_config_ok){ | |
154 | - change_and_wait(status_device_config,status_device_config_ok); | |
155 | - } | |
156 | - apply_config_(device_index,params); | |
157 | - init_buffer(); | |
158 | - change_and_wait(status_process,status_processing); | |
159 | -} | |
160 | - | |
161 | -void input_thread_t::apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params) | |
162 | -{ | |
163 | - | |
164 | - WAVEFORMATEXTENSIBLE form; | |
165 | - if(wasapi_input_) | |
166 | - { | |
167 | - if(wasapi_input_->is_start()) | |
147 | + ; | |
148 | + DOUT(L"##### input_threadは終了!" << endl); | |
149 | + if(wasapi_input_ && wasapi_input_->is_start()) | |
168 | 150 | { |
169 | 151 | wasapi_input_->stop(); |
170 | 152 | } |
171 | 153 | wasapi_input_.reset(); |
172 | 154 | }; |
173 | 155 | |
174 | - //bits_pair bits = {params.bits,params.valid_bits}; | |
175 | - //make_wave_format(form,params.sample_rate,params.channel,bits); | |
156 | + void input_thread_t::apply_config(int device_index,wasapi_device_manager::device_info::params_t& params) | |
157 | + { | |
158 | + if(status() != status_device_config_ok){ | |
159 | + change_and_wait(status_device_config,status_device_config_ok); | |
160 | + } | |
161 | + apply_config_(device_index,params); | |
162 | + init_buffer(); | |
163 | + change_and_wait(status_process,status_processing); | |
164 | + } | |
165 | + | |
166 | + void input_thread_t::apply_config_(int device_index,wasapi_device_manager::device_info::params_t& params) | |
167 | + { | |
176 | 168 | |
177 | - try { | |
178 | - if(params.exclusive_mode) | |
169 | + WAVEFORMATEXTENSIBLE form; | |
170 | + if(wasapi_input_) | |
179 | 171 | { |
180 | - if(params.event_mode){ | |
181 | - wasapi_input_.reset(new sf::wasapi_capture_exclusive_event(device_index,params)); | |
182 | - } else { | |
183 | - wasapi_input_.reset(new sf::wasapi_capture_exclusive_timer(device_index,params)); | |
184 | - }; | |
185 | - } else { | |
186 | - if(params.event_mode) | |
172 | + if(wasapi_input_->is_start()) | |
173 | + { | |
174 | + wasapi_input_->stop(); | |
175 | + } | |
176 | + wasapi_input_.reset(); | |
177 | + }; | |
178 | + | |
179 | + //bits_pair bits = {params.bits,params.valid_bits}; | |
180 | + //make_wave_format(form,params.sample_rate,params.channel,bits); | |
181 | + | |
182 | + try { | |
183 | + if(params.exclusive_mode) | |
187 | 184 | { |
188 | - wasapi_input_.reset(new sf::wasapi_capture_shared_event(device_index,params)); | |
185 | + if(params.event_mode){ | |
186 | + wasapi_input_.reset(new sf::wasapi_capture_exclusive_event(device_index,params)); | |
187 | + } else { | |
188 | + wasapi_input_.reset(new sf::wasapi_capture_exclusive_timer(device_index,params)); | |
189 | + }; | |
189 | 190 | } else { |
190 | - wasapi_input_.reset(new sf::wasapi_capture_shared_timer(device_index,params)); | |
191 | + if(params.event_mode) | |
192 | + { | |
193 | + wasapi_input_.reset(new sf::wasapi_capture_shared_event(device_index,params)); | |
194 | + } else { | |
195 | + wasapi_input_.reset(new sf::wasapi_capture_shared_timer(device_index,params)); | |
196 | + } | |
191 | 197 | } |
192 | - } | |
193 | - } catch (win32_error_exception& e) | |
194 | - { | |
198 | + } catch (win32_error_exception& e) | |
199 | + { | |
195 | 200 | |
196 | - //window_->message_box((boost::wformat(L"WASAPI初期化エラーが発生しました。設定パラメータを見なおしてください。%s") % e.error()).str(),wstring(L"WASAPI初期化エラー")); | |
197 | - throw; | |
198 | - } | |
201 | + //window_->message_box((boost::wformat(L"WASAPI初期化エラーが発生しました。設定パラメータを見なおしてください。%s") % e.error()).str(),wstring(L"WASAPI初期化エラー")); | |
202 | + throw; | |
203 | + } | |
199 | 204 | |
200 | - wasapi_device_manager::instance()->select_input_device(device_index); | |
201 | - wasapi_device_manager::instance()->current_input_device().params = params; | |
205 | + wasapi_device_manager::instance()->select_input_device(device_index); | |
206 | + wasapi_device_manager::instance()->current_input_device().params = params; | |
202 | 207 | |
203 | -} | |
208 | + } | |
204 | 209 | |
205 | 210 | //void input_thread_t::init_buffer() |
206 | 211 | //{ |
@@ -13,7 +13,7 @@ | ||
13 | 13 | // STL |
14 | 14 | |
15 | 15 | #define DIRECTINPUT_VERSION 0x0800 |
16 | -#define BOOST_ALL_NO_LIB | |
16 | +//#define BOOST_ALL_NO_LIB | |
17 | 17 | |
18 | 18 | #include <stdint.h> |
19 | 19 | #include <tchar.h> |
@@ -85,6 +85,11 @@ namespace sf { | ||
85 | 85 | |
86 | 86 | ref class DeviceWatcherAdapter |
87 | 87 | { |
88 | + public: | |
89 | + virtual ~DeviceWatcherAdapter() | |
90 | + { | |
91 | + added_.disconnect_all_slots(); | |
92 | + }; | |
88 | 93 | internal: |
89 | 94 | DeviceWatcherAdapter(en::DeviceClass deviceClass = en::DeviceClass::AudioRender) |
90 | 95 | { |
@@ -95,7 +100,6 @@ namespace sf { | ||
95 | 100 | watcher_->Removed += ref new f::TypedEventHandler<en::DeviceWatcher^ , en::DeviceInformationUpdate^ >(this,&DeviceWatcherAdapter::Removed); |
96 | 101 | watcher_->Stopped += ref new f::TypedEventHandler<en::DeviceWatcher^ , Platform::Object^ >(this,&DeviceWatcherAdapter::Stopped); |
97 | 102 | } |
98 | - | |
99 | 103 | boost::signals2::signal<void (en::DeviceWatcher^ sender |
100 | 104 | , en::DeviceInformation^ deviceInterface) >& added(){return added_;} |
101 | 105 | boost::signals2::signal<void (en::DeviceWatcher^ sender, |
@@ -108,11 +112,11 @@ namespace sf { | ||
108 | 112 | Platform::Object^ obj) >& stopped() {return stopped_;} |
109 | 113 | void start() |
110 | 114 | { |
111 | - watcher_->Start(); | |
115 | + watcher_->Start(); | |
112 | 116 | } |
113 | 117 | void stop() |
114 | 118 | { |
115 | - watcher_->Stop(); | |
119 | + watcher_->Stop(); | |
116 | 120 | } |
117 | 121 | private: |
118 | 122 | void Added(en::DeviceWatcher^ sender, en::DeviceInformation^ deviceInterface) |
@@ -246,7 +250,20 @@ namespace sf { | ||
246 | 250 | int current_output_device_index() const {return output_device_index_;} |
247 | 251 | int current_input_device_index() const {return input_device_index_;} |
248 | 252 | static const std::wstring & base_directory() {return base_directory_;}; |
249 | - private: | |
253 | + | |
254 | + // 列挙が関連するまで待つ | |
255 | + void wait_enum_devices() | |
256 | + { | |
257 | + while(!output_enum_completed_ || !input_enum_completed_) | |
258 | + { | |
259 | + Sleep(1); | |
260 | + } | |
261 | + } | |
262 | + | |
263 | + void stop_watching(); | |
264 | + void save_params(); | |
265 | + | |
266 | + private: | |
250 | 267 | void output_added(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformation^ deviceInfo); |
251 | 268 | void output_enumeration_completed(en::DeviceWatcher^ sender, Platform::Object^ obj); |
252 | 269 | void output_updated(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo); |
@@ -260,15 +277,30 @@ namespace sf { | ||
260 | 277 | void input_stopped(en::DeviceWatcher^ sender, Platform::Object^ obj); |
261 | 278 | |
262 | 279 | int get_device_infos(Windows::Devices::Enumeration::DeviceClass data_flow, std::vector<device_info>& infos,const std::wstring& idd); |
263 | - int output_device_index_; | |
280 | + | |
281 | + | |
282 | + int output_device_index_; | |
264 | 283 | int input_device_index_; |
265 | 284 | std::vector<device_info> output_device_infos_; |
266 | 285 | std::vector<device_info> input_device_infos_; |
267 | 286 | static const std::wstring base_directory_; |
268 | 287 | std::wstring config_path_; |
269 | - DeviceWatcherAdapter^ output_watcher_adapter_; | |
288 | + // 出力デバイス監視アダプタ | |
289 | + DeviceWatcherAdapter^ output_watcher_adapter_; | |
290 | + | |
291 | + // 入力デバイス監視アダプタ | |
270 | 292 | DeviceWatcherAdapter^ input_watcher_adapter_; |
271 | - bool enum_completed_; | |
293 | + | |
294 | + // 出力デバイスの列挙が完了したか | |
295 | + bool output_enum_completed_; | |
296 | + // 入力デバイスの列挙が完了したか | |
297 | + bool input_enum_completed_; | |
298 | + | |
299 | + std::wstring output_id_; | |
300 | + std::wstring input_id_; | |
301 | + std::wstring default_output_id_; | |
302 | + std::wstring default_input_id_; | |
303 | + | |
272 | 304 | }; |
273 | 305 | |
274 | 306 | // タイマーモードのポリシークラス |
@@ -422,6 +454,7 @@ namespace sf { | ||
422 | 454 | // 再生レイテンシ |
423 | 455 | REFERENCE_TIME latency_;/* ms */ |
424 | 456 | REFERENCE_TIME actual_latency_; |
457 | + | |
425 | 458 | }; |
426 | 459 | |
427 | 460 | typedef wasapi_base<wasapi_shared_policy,wasapi_timer_policy> wasapi_shared_timer; |
@@ -461,6 +494,7 @@ namespace sf { | ||
461 | 494 | hr_ = S_OK; |
462 | 495 | // Get the pointer for the Audio Client |
463 | 496 | punkAudioInterface->QueryInterface( IID_PPV_ARGS(&ptr_) ); |
497 | + punkAudioInterface->Release(); | |
464 | 498 | if( nullptr == ptr_ ) |
465 | 499 | { |
466 | 500 | hr_ = E_FAIL; |
@@ -20,14 +20,14 @@ | ||
20 | 20 | <ConfigurationType>Application</ConfigurationType> |
21 | 21 | <UseDebugLibraries>true</UseDebugLibraries> |
22 | 22 | <CharacterSet>Unicode</CharacterSet> |
23 | - <PlatformToolset>v110</PlatformToolset> | |
23 | + <PlatformToolset>v120_CTP_Nov2012</PlatformToolset> | |
24 | 24 | </PropertyGroup> |
25 | 25 | <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |
26 | 26 | <ConfigurationType>Application</ConfigurationType> |
27 | 27 | <UseDebugLibraries>false</UseDebugLibraries> |
28 | 28 | <WholeProgramOptimization>true</WholeProgramOptimization> |
29 | 29 | <CharacterSet>Unicode</CharacterSet> |
30 | - <PlatformToolset>v110</PlatformToolset> | |
30 | + <PlatformToolset>v120_CTP_Nov2012</PlatformToolset> | |
31 | 31 | </PropertyGroup> |
32 | 32 | <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
33 | 33 | <ImportGroup Label="ExtensionSettings"> |
@@ -41,474 +41,513 @@ using namespace Platform; | ||
41 | 41 | using namespace Microsoft::WRL; |
42 | 42 | |
43 | 43 | namespace sf { |
44 | - const wstring wasapi_device_manager::base_directory_(L""/* Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data() */); | |
45 | - const int wasapi_device_manager::sample_rates[NUM_SAMPLE_RATE] = {8000,11025,16000,22050,24000,32000,44100,48000,88200,96000,176400,192000}; | |
46 | - const bits_pair wasapi_device_manager::sample_bits[NUM_SAMPLE_BITS] = {{8,8},{16,16},{24,24},{32,24},{32,32},{32,WAVE_FORMAT_IEEE_FLOAT}}; | |
47 | - | |
48 | - void make_wave_format(WAVEFORMATEXTENSIBLE& format,int sample_rate,int channels,bits_pair b,uint32_t type,const GUID& sub_type) | |
49 | - { | |
50 | - ZeroMemory(&format,sizeof(WAVEFORMATEXTENSIBLE)); | |
51 | - format.Format.wFormatTag = type; | |
52 | - format.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); | |
53 | - format.SubFormat = sub_type; | |
54 | - format.Format.nSamplesPerSec = sample_rate; | |
55 | - format.Format.nChannels = channels; | |
56 | - format.Format.wBitsPerSample = b.bits_per_sample; | |
57 | - format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * format.Format.nChannels; | |
58 | - format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec * format.Format.nBlockAlign; | |
59 | - format.Samples.wValidBitsPerSample = b.valid_bits_per_sample; | |
60 | - | |
61 | - format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; | |
62 | - }; | |
63 | - | |
64 | - void make_wave_format(WAVEFORMATEX& format,int sample_rate,int channels,int bits,uint32_t type) | |
65 | - { | |
66 | - ZeroMemory(&format,sizeof(WAVEFORMATEX)); | |
67 | - format.wFormatTag = type; | |
68 | - format.nSamplesPerSec = sample_rate; | |
69 | - format.nChannels = channels; | |
70 | - format.wBitsPerSample = bits; | |
71 | - format.nBlockAlign = (format.wBitsPerSample / 8) * format.nChannels; | |
72 | - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; | |
73 | - }; | |
74 | - | |
75 | - struct prop_variant | |
76 | - { | |
77 | - prop_variant() | |
78 | - { | |
79 | - PropVariantInit(&value_); | |
80 | - } | |
81 | - | |
82 | - ~prop_variant() | |
83 | - { | |
84 | - PropVariantClear(&value_); | |
85 | - } | |
86 | - | |
87 | - PROPVARIANT* get(){ return &value_;}; | |
88 | - | |
89 | - PROPVARIANT* operator &(){return get();} | |
90 | - | |
91 | - operator PROPVARIANT*() {return get();} | |
92 | - | |
93 | - private: | |
94 | - PROPVARIANT value_; | |
95 | - }; | |
96 | - | |
97 | - | |
98 | - wasapi_device_manager::wasapi_device_manager() | |
99 | - : output_device_index_(0),input_device_index_(0),enum_completed_(false) | |
100 | - { | |
101 | - | |
102 | - config_path_.append(base_directory_).append(L"\\wasapi_device_manager.config.xml"); | |
103 | - boost::filesystem::wpath config_path(config_path_); | |
104 | - | |
105 | - std::wstring output_id; | |
106 | - std::wstring input_id; | |
107 | - | |
108 | - if(boost::filesystem::exists(config_path)) | |
109 | - { | |
110 | - try { | |
111 | - boost::filesystem::wifstream f(config_path); | |
112 | - boost::archive::xml_wiarchive ar(f); | |
113 | - ar & boost::serialization::make_nvp("output_device_id",output_id); | |
114 | - ar & boost::serialization::make_nvp("input_device_id" ,input_id); | |
115 | - } catch(...) | |
116 | - { | |
117 | - output_id = input_id = L""; | |
118 | - boost::filesystem::remove(config_path); | |
119 | - } | |
120 | - } | |
121 | - | |
122 | - //watcher_ = DeviceInformation::CreateWatcher(); | |
123 | - //adapter_ = ref new typed_event_handler_adapter<DeviceWatcher^,DeviceInformation^>(boost::bind(&wasapi_device_manager::added,this,_1,_2)); | |
124 | - // watcher_->Added += adapter_->get(); | |
125 | - //watcher_->Added += (ref new typed_event_handler_adapter<DeviceWatcher^,DeviceInformation^>(boost::bind(&wasapi_device_manager::added,this,_1,_2)))->get(); | |
126 | - //watcher_->Start(); | |
127 | - | |
128 | - output_watcher_adapter_ = ref new DeviceWatcherAdapter(en::DeviceClass::AudioRender); | |
129 | - output_watcher_adapter_->added().connect(boost::bind(&wasapi_device_manager::output_added,this,_1,_2)); | |
130 | - output_watcher_adapter_->enumration_completed().connect(boost::bind(&wasapi_device_manager::output_enumeration_completed,this,_1,_2)); | |
131 | - output_watcher_adapter_->removed().connect(boost::bind(&wasapi_device_manager::output_removed,this,_1,_2)); | |
132 | - output_watcher_adapter_->updated().connect(boost::bind(&wasapi_device_manager::output_updated,this,_1,_2)); | |
133 | - output_watcher_adapter_->stopped().connect(boost::bind(&wasapi_device_manager::output_stopped,this,_1,_2)); | |
134 | - output_watcher_adapter_->start(); | |
44 | + const wstring wasapi_device_manager::base_directory_(L"."/* Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data() */); | |
45 | + const int wasapi_device_manager::sample_rates[NUM_SAMPLE_RATE] = {8000,11025,16000,22050,24000,32000,44100,48000,88200,96000,176400,192000}; | |
46 | + const bits_pair wasapi_device_manager::sample_bits[NUM_SAMPLE_BITS] = {{8,8},{16,16},{24,24},{32,24},{32,32},{32,WAVE_FORMAT_IEEE_FLOAT}}; | |
47 | + | |
48 | + void make_wave_format(WAVEFORMATEXTENSIBLE& format,int sample_rate,int channels,bits_pair b,uint32_t type,const GUID& sub_type) | |
49 | + { | |
50 | + ZeroMemory(&format,sizeof(WAVEFORMATEXTENSIBLE)); | |
51 | + format.Format.wFormatTag = type; | |
52 | + format.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); | |
53 | + format.SubFormat = sub_type; | |
54 | + format.Format.nSamplesPerSec = sample_rate; | |
55 | + format.Format.nChannels = channels; | |
56 | + format.Format.wBitsPerSample = b.bits_per_sample; | |
57 | + format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * format.Format.nChannels; | |
58 | + format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec * format.Format.nBlockAlign; | |
59 | + format.Samples.wValidBitsPerSample = b.valid_bits_per_sample; | |
60 | + | |
61 | + format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; | |
62 | + }; | |
63 | + | |
64 | + void make_wave_format(WAVEFORMATEX& format,int sample_rate,int channels,int bits,uint32_t type) | |
65 | + { | |
66 | + ZeroMemory(&format,sizeof(WAVEFORMATEX)); | |
67 | + format.wFormatTag = type; | |
68 | + format.nSamplesPerSec = sample_rate; | |
69 | + format.nChannels = channels; | |
70 | + format.wBitsPerSample = bits; | |
71 | + format.nBlockAlign = (format.wBitsPerSample / 8) * format.nChannels; | |
72 | + format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; | |
73 | + }; | |
74 | + | |
75 | + struct prop_variant | |
76 | + { | |
77 | + prop_variant() | |
78 | + { | |
79 | + PropVariantInit(&value_); | |
80 | + } | |
81 | + | |
82 | + ~prop_variant() | |
83 | + { | |
84 | + PropVariantClear(&value_); | |
85 | + } | |
86 | + | |
87 | + PROPVARIANT* get(){ return &value_;}; | |
88 | + | |
89 | + PROPVARIANT* operator &(){return get();} | |
90 | + | |
91 | + operator PROPVARIANT*() {return get();} | |
92 | + | |
93 | + private: | |
94 | + PROPVARIANT value_; | |
95 | + }; | |
96 | + | |
97 | + | |
98 | + wasapi_device_manager::wasapi_device_manager() | |
99 | + : output_device_index_(-1),input_device_index_(-1),output_enum_completed_(false),input_enum_completed_(false) | |
100 | + { | |
101 | + | |
102 | + config_path_.append(base_directory_).append(L"\\wasapi_device_manager.config.xml"); | |
103 | + boost::filesystem::wpath config_path(config_path_); | |
104 | + | |
105 | + | |
106 | + if(boost::filesystem::exists(config_path)) | |
107 | + { | |
108 | + try { | |
109 | + boost::filesystem::wifstream f(config_path); | |
110 | + boost::archive::xml_wiarchive ar(f); | |
111 | + ar & boost::serialization::make_nvp("output_device_id",output_id_); | |
112 | + ar & boost::serialization::make_nvp("input_device_id" ,input_id_); | |
113 | + } catch(...) | |
114 | + { | |
115 | + output_id_ = input_id_ = L""; | |
116 | + boost::filesystem::remove(config_path); | |
117 | + } | |
118 | + } | |
119 | + | |
120 | + default_output_id_ = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default)->Data(); | |
121 | + default_input_id_ = MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default)->Data(); | |
122 | + | |
123 | + //watcher_ = DeviceInformation::CreateWatcher(); | |
124 | + //adapter_ = ref new typed_event_handler_adapter<DeviceWatcher^,DeviceInformation^>(boost::bind(&wasapi_device_manager::added,this,_1,_2)); | |
125 | + // watcher_->Added += adapter_->get(); | |
126 | + //watcher_->Added += (ref new typed_event_handler_adapter<DeviceWatcher^,DeviceInformation^>(boost::bind(&wasapi_device_manager::added,this,_1,_2)))->get(); | |
127 | + //watcher_->Start(); | |
128 | + | |
129 | + output_watcher_adapter_ = ref new DeviceWatcherAdapter(en::DeviceClass::AudioRender); | |
130 | + output_watcher_adapter_->added().connect(boost::bind(&wasapi_device_manager::output_added,this,_1,_2)); | |
131 | + output_watcher_adapter_->enumration_completed().connect(boost::bind(&wasapi_device_manager::output_enumeration_completed,this,_1,_2)); | |
132 | + output_watcher_adapter_->removed().connect(boost::bind(&wasapi_device_manager::output_removed,this,_1,_2)); | |
133 | + output_watcher_adapter_->updated().connect(boost::bind(&wasapi_device_manager::output_updated,this,_1,_2)); | |
134 | + output_watcher_adapter_->stopped().connect(boost::bind(&wasapi_device_manager::output_stopped,this,_1,_2)); | |
135 | + output_watcher_adapter_->start(); | |
135 | 136 | |
136 | 137 | input_watcher_adapter_ = ref new DeviceWatcherAdapter(en::DeviceClass::AudioCapture); |
137 | - input_watcher_adapter_->added().connect(boost::bind(&wasapi_device_manager::input_added,this,_1,_2)); | |
138 | - input_watcher_adapter_->enumration_completed().connect(boost::bind(&wasapi_device_manager::input_enumeration_completed,this,_1,_2)); | |
139 | - input_watcher_adapter_->removed().connect(boost::bind(&wasapi_device_manager::input_removed,this,_1,_2)); | |
140 | - input_watcher_adapter_->updated().connect(boost::bind(&wasapi_device_manager::input_updated,this,_1,_2)); | |
141 | - input_watcher_adapter_->stopped().connect(boost::bind(&wasapi_device_manager::input_stopped,this,_1,_2)); | |
142 | - input_watcher_adapter_->start(); | |
143 | - | |
144 | - //// IMMDeviceEnumeratorの取得 | |
145 | - //THROW_IF_ERR( | |
146 | - // CoCreateInstance( | |
147 | - // __uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, | |
148 | - // IID_PPV_ARGS(&device_collection_))); | |
149 | - //task<DeviceInformationCollection^> t(DeviceInformation::FindAllAsync(DeviceClass::AudioRender)); | |
150 | - //device_collection_ = t.get(); | |
151 | - | |
152 | - // 出力エンドポイントの取得 | |
153 | - /* | |
154 | - output_device_index_ = get_device_infos(Windows::Devices::Enumeration::DeviceClass::AudioRender,output_device_infos_,output_id); | |
155 | - // 出力エンドポイントの能力を調査する | |
156 | - for(int d = 0;d < output_device_infos_.size();++d) | |
157 | - { | |
158 | - IAudioClient2Ptr c; | |
159 | - // オーディオクライアントを取得 | |
160 | - // THROW_IF_ERR(ActivateAudioInterface(output_device_infos_[d].id_.c_str(),__uuidof(IAudioClient2),&c)); | |
161 | - { | |
162 | - ComPtr<IActivateAudioInterfaceAsyncOperation> asyncOpPtr; | |
163 | - IActivateAudioInterfaceAsyncOperation* asyncOp; | |
164 | - ComPtr<ActivateAudioInterfaceCompletionHandler> handler(Make<ActivateAudioInterfaceCompletionHandler>()); | |
165 | - HRESULT hr = ActivateAudioInterfaceAsync(output_device_infos_[d].id_.c_str(),__uuidof(IAudioClient2),nullptr,handler.Get(),&asyncOp); | |
166 | - asyncOpPtr.Attach(asyncOp); | |
167 | - if(SUCCEEDED(hr)){ | |
168 | - handler->wait(); | |
169 | - if(handler->ResultCode() == S_OK) | |
170 | - { | |
171 | - c = handler->AudioClient(); | |
172 | - } else { | |
173 | - throw win32_error_exception(handler->ResultCode()); | |
174 | - } | |
175 | - } else { | |
176 | - throw win32_error_exception(handler->ResultCode()); | |
177 | - } | |
178 | - } | |
179 | - c->GetDevicePeriod(&(output_device_infos_[d].latency_default_),&(output_device_infos_[d].latency_minimum_)); | |
180 | - if(output_device_infos_[d].params.latency == 0 | |
181 | - || output_device_infos_[d].params.latency < output_device_infos_[d].latency_minimum_ ) | |
182 | - { | |
183 | - output_device_infos_[d].params.latency = output_device_infos_[d].latency_default_; | |
184 | - } | |
185 | - | |
186 | - #ifdef _DEBUG | |
187 | - wdout << output_device_infos_[d].name_ << endl; | |
188 | - wdout << boost::wformat(L"latency default:%d min:%d") % output_device_infos_[d].latency_default_ % output_device_infos_[d].latency_minimum_ << endl; | |
189 | - #endif | |
190 | - for(int bits = 0;bits < NUM_SAMPLE_BITS;++bits) | |
191 | - { | |
192 | - for(int channel = 1;channel < 3;++channel) | |
193 | - { | |
194 | - for(int rate = 0;rate < NUM_SAMPLE_RATE;++rate) | |
195 | - { | |
196 | - sf::co_task_memory<WAVEFORMATEXTENSIBLE> a,a1; | |
197 | - WAVEFORMATEXTENSIBLE f; | |
198 | - | |
199 | - // make_wave_fomat(f,sample_rates[rate],channel,sample_bits[bits]); | |
200 | - if(sample_bits[bits].valid_bits_per_sample == WAVE_FORMAT_IEEE_FLOAT) | |
201 | - { | |
202 | - bits_pair b ={sample_bits[bits].bits_per_sample,sample_bits[bits].bits_per_sample}; | |
203 | - make_wave_format(f,sample_rates[rate],channel,b,WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); | |
204 | - } else { | |
205 | - make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_PCM); | |
206 | - } | |
207 | - | |
208 | - // 排他モード | |
209 | - HRESULT hr = c->IsFormatSupported( | |
210 | - AUDCLNT_SHAREMODE_EXCLUSIVE,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a)); | |
211 | - if(hr == S_OK){ | |
212 | - output_device_infos_[d].support_formats_[AUDCLNT_SHAREMODE_EXCLUSIVE][ sample_bits[bits].bits_per_sample ][sample_bits[bits].valid_bits_per_sample][channel][sample_rates[rate]] = 0; | |
213 | - #ifdef _DEBUG | |
214 | - wdout << boost::wformat(L"|exc |bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") % sample_bits[bits].bits_per_sample % sample_bits[bits].valid_bits_per_sample % channel % sample_rates[rate] % (hr == S_OK?L"OK":L"NG") << endl; | |
215 | - #endif } | |
216 | - | |
217 | - // make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE); | |
218 | - // 共有モード | |
219 | - hr = c->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a1)); | |
220 | - if(hr == S_OK){ | |
221 | - output_device_infos_[d] | |
222 | - .support_formats_ | |
223 | - [AUDCLNT_SHAREMODE_SHARED] | |
224 | - [ sample_bits[bits].bits_per_sample ] | |
225 | - [sample_bits[bits].valid_bits_per_sample] | |
226 | - [channel][sample_rates[rate]] | |
227 | - = 0; | |
228 | - #ifdef _DEBUG | |
229 | - wdout << boost::wformat(L"|share|bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") | |
230 | - % sample_bits[bits].bits_per_sample | |
231 | - % sample_bits[bits].valid_bits_per_sample | |
232 | - % channel % sample_rates[rate] | |
233 | - % (hr == S_OK?L"OK":L"NG") << endl; | |
234 | - | |
235 | - #endif | |
236 | - } | |
237 | - } | |
238 | - } | |
239 | - } | |
240 | - #ifdef _DEBUG | |
241 | - wdout << "-------------------------------" << std::endl; | |
242 | - #endif | |
243 | - } | |
244 | - // safe_release(c); | |
245 | - } | |
246 | - | |
247 | - // 入力エンドポイントの取得 | |
248 | - input_device_index_ = get_device_infos(DeviceClass::AudioCapture,input_device_infos_,input_id); | |
249 | - // 出力エンドポイントの能力を調査する | |
250 | - for(int d = 0;d < input_device_infos_.size();++d) | |
251 | - { | |
252 | - IAudioClient2Ptr c; | |
253 | - // オーディオクライアントを取得 | |
254 | - // THROW_IF_ERR(ActivateAudioInterface(input_device_infos_[d].id_.c_str(),__uuidof(IAudioClient2),&c) ); | |
255 | - { | |
256 | - ComPtr<IActivateAudioInterfaceAsyncOperation> asyncOpPtr; | |
257 | - IActivateAudioInterfaceAsyncOperation* asyncOp; | |
258 | - ComPtr<ActivateAudioInterfaceCompletionHandler> handler(Make<ActivateAudioInterfaceCompletionHandler>()); | |
259 | - HRESULT hr = ActivateAudioInterfaceAsync(input_device_infos_[d].id_.c_str(),__uuidof(IAudioClient2),nullptr,handler.Get(),&asyncOp); | |
260 | - asyncOpPtr.Attach(asyncOp); | |
261 | - if(SUCCEEDED(hr)){ | |
262 | - handler->wait(); | |
263 | - if(handler->ResultCode() == S_OK) | |
264 | - { | |
265 | - c = handler->AudioClient(); | |
266 | - } else { | |
267 | - throw win32_error_exception(handler->ResultCode()); | |
268 | - } | |
269 | - } else { | |
270 | - throw win32_error_exception(handler->ResultCode()); | |
271 | - } | |
272 | - } | |
273 | - c->GetDevicePeriod(&(input_device_infos_[d].latency_default_),&(input_device_infos_[d].latency_minimum_)); | |
274 | - if(input_device_infos_[d].params.latency == 0 || input_device_infos_[d].params.latency < input_device_infos_[d].latency_minimum_ ){ | |
275 | - input_device_infos_[d].params.latency = input_device_infos_[d].latency_default_; | |
276 | - } | |
277 | - | |
278 | - #ifdef _DEBUG | |
279 | - wdout << input_device_infos_[d].display_name_ << endl; | |
280 | - wdout << boost::wformat(L"latency default:%d min:%d") % input_device_infos_[d].latency_default_ % input_device_infos_[d].latency_minimum_ << endl; | |
281 | - #endif | |
282 | - for(int bits = 0;bits < NUM_SAMPLE_BITS;++bits) | |
283 | - { | |
284 | - for(int channel = 1;channel < 3;++channel) | |
285 | - { | |
286 | - for(int rate = 0;rate < NUM_SAMPLE_RATE;++rate) | |
287 | - { | |
288 | - sf::co_task_memory<WAVEFORMATEXTENSIBLE> a,a1; | |
289 | - WAVEFORMATEXTENSIBLE f; | |
290 | - | |
291 | - // make_wave_fomat(f,sample_rates[rate],channel,sample_bits[bits]); | |
292 | - if(sample_bits[bits].valid_bits_per_sample == WAVE_FORMAT_IEEE_FLOAT) | |
293 | - { | |
294 | - bits_pair b ={sample_bits[bits].bits_per_sample,sample_bits[bits].bits_per_sample}; | |
295 | - make_wave_format(f,sample_rates[rate],channel,b,WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); | |
296 | - } else { | |
297 | - make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_PCM); | |
298 | - } | |
299 | - | |
300 | - // 排他モード | |
301 | - HRESULT hr = c->IsFormatSupported( | |
302 | - AUDCLNT_SHAREMODE_EXCLUSIVE,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a)); | |
303 | - if(hr == S_OK){ | |
304 | - input_device_infos_[d] | |
305 | - .support_formats_ | |
306 | - [AUDCLNT_SHAREMODE_EXCLUSIVE] | |
307 | - [ sample_bits[bits].bits_per_sample ] | |
308 | - [sample_bits[bits].valid_bits_per_sample] | |
309 | - [channel] | |
310 | - [sample_rates[rate]] = 0; | |
311 | - #ifdef _DEBUG | |
312 | - wdout << boost::wformat(L"|exc |bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") | |
313 | - % sample_bits[bits].bits_per_sample | |
314 | - % sample_bits[bits].valid_bits_per_sample | |
315 | - % channel % sample_rates[rate] | |
316 | - % (hr == S_OK?L"OK":L"NG") << endl; | |
317 | - #endif } | |
318 | - | |
319 | - // make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE); | |
320 | - // 共有モード | |
321 | - hr = c->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a1)); | |
322 | - if(hr == S_OK){ | |
323 | - input_device_infos_[d]. | |
324 | - support_formats_ | |
325 | - [AUDCLNT_SHAREMODE_SHARED] | |
326 | - [sample_bits[bits].bits_per_sample ] | |
327 | - [sample_bits[bits].valid_bits_per_sample] | |
328 | - [channel] | |
329 | - [sample_rates[rate]] = 0; | |
330 | - #ifdef _DEBUG | |
331 | - wdout << boost::wformat(L"|share|bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") | |
332 | - % sample_bits[bits].bits_per_sample | |
333 | - % sample_bits[bits].valid_bits_per_sample | |
334 | - % channel | |
335 | - % sample_rates[rate] | |
336 | - % (hr == S_OK?L"OK":L"NG") << endl; | |
337 | - | |
338 | - #endif | |
339 | - } | |
340 | - } | |
341 | - } | |
342 | - } | |
343 | - #ifdef _DEBUG | |
344 | - wdout << "-------------------------------" << std::endl; | |
345 | - #endif | |
346 | - } | |
347 | - // safe_release(c); | |
348 | - } | |
349 | - */ | |
350 | - }// | |
351 | - | |
352 | - int wasapi_device_manager::get_device_infos(DeviceClass data_flow, std::vector<device_info>& infos,const std::wstring& idd) | |
353 | - { | |
354 | - | |
355 | - // 対象デバイスを列挙する | |
356 | - task<DeviceInformationCollection^> t((DeviceInformation::FindAllAsync(data_flow))); | |
357 | - t.wait(); | |
358 | - DeviceInformationCollection^ collection = t.get(); | |
359 | - int current_index = 0; | |
360 | - bool found = false; | |
361 | - Platform::String^ default_id = ref new Platform::String(); | |
362 | - switch(data_flow) | |
363 | - { | |
364 | - case Windows::Devices::Enumeration::DeviceClass::AudioRender: | |
365 | - default_id = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default); | |
366 | - break; | |
367 | - case Windows::Devices::Enumeration::DeviceClass::AudioCapture: | |
368 | - default_id = MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default); | |
369 | - break; | |
370 | - } | |
371 | - | |
372 | - | |
373 | - for(int i = 0 ,end = collection->Size;i < end;++i) | |
374 | - { | |
375 | - DeviceInformation^ info = collection->GetAt(i); | |
376 | - infos.push_back(device_info(info)); | |
377 | - if(info->Id == default_id) | |
378 | - { | |
379 | - infos[i].is_default_ = true; | |
380 | - } | |
381 | - | |
382 | - if(idd == wstring(info->Id->Data()) ) | |
383 | - { | |
384 | - infos[i].is_selected_ = true; | |
385 | - current_index = i; | |
386 | - found = true; | |
387 | - } | |
388 | - } | |
389 | - | |
390 | - if(!found) | |
391 | - { | |
392 | - for(int i = 0,end = infos.size();i < end;++i) | |
393 | - { | |
394 | - if(infos[i].is_default_) | |
395 | - { | |
396 | - current_index = i; | |
397 | - infos[i].is_selected_ = true; | |
398 | - } | |
399 | - } | |
400 | - | |
401 | - } | |
402 | - return current_index; | |
403 | - } | |
404 | - | |
405 | - wasapi_device_manager::~wasapi_device_manager() | |
406 | - { | |
407 | - input_watcher_adapter_->stop(); | |
408 | - output_watcher_adapter_->stop(); | |
409 | - //for(int i = 0; i < | |
410 | - //safe_release(device_collection_); | |
411 | - //safe_release(device_collection_); | |
412 | - //safe_release(device_collection_); | |
413 | - | |
414 | - // 設定の保存 | |
415 | - try{ | |
416 | - boost::filesystem::wpath config_path(config_path_); | |
417 | - boost::filesystem::wofstream f(config_path,std::ios_base::out | std::ios_base::trunc); | |
418 | - boost::archive::xml_woarchive ar(f); | |
419 | - ar & boost::serialization::make_nvp("output_device_id",current_output_device().id_); | |
420 | - ar & boost::serialization::make_nvp("input_device_id" ,current_input_device().id_); | |
421 | - }catch(...) { | |
422 | - | |
423 | - } | |
424 | - | |
425 | - } | |
426 | - | |
427 | - wasapi_device_manager::device_info::device_info | |
428 | - (DeviceInformation^ info) | |
429 | - : id_(info->Id->Data()), | |
430 | - name_(info->Name->Data()), | |
431 | - display_name_(dynamic_cast<String^>(info->Properties->Lookup(L"System.ItemNameDisplay"))->Data()), | |
432 | - is_enabled_(info->IsEnabled),is_selected_(false),is_default_(info->IsDefault) | |
433 | - { | |
434 | - boost::filesystem::wpath | |
435 | - config_path(wasapi_device_manager::base_directory() + L"\\" + id_ + L".xml"); | |
436 | - if(boost::filesystem::exists(config_path)) | |
437 | - { | |
438 | - try{ | |
439 | - boost::filesystem::wifstream ifile(config_path); | |
440 | - boost::archive::xml_wiarchive ar(ifile); | |
441 | - ar >> BOOST_SERIALIZATION_NVP(params); | |
442 | - } catch (...) | |
443 | - { | |
444 | - // ファイル読み込みに問題がある場合はファイルを消す。 | |
445 | - boost::filesystem::remove(config_path); | |
446 | - } | |
447 | - } | |
138 | + input_watcher_adapter_->added().connect(boost::bind(&wasapi_device_manager::input_added,this,_1,_2)); | |
139 | + input_watcher_adapter_->enumration_completed().connect(boost::bind(&wasapi_device_manager::input_enumeration_completed,this,_1,_2)); | |
140 | + input_watcher_adapter_->removed().connect(boost::bind(&wasapi_device_manager::input_removed,this,_1,_2)); | |
141 | + input_watcher_adapter_->updated().connect(boost::bind(&wasapi_device_manager::input_updated,this,_1,_2)); | |
142 | + input_watcher_adapter_->stopped().connect(boost::bind(&wasapi_device_manager::input_stopped,this,_1,_2)); | |
143 | + input_watcher_adapter_->start(); | |
144 | + | |
145 | + }// | |
146 | + | |
147 | + int wasapi_device_manager::get_device_infos(DeviceClass data_flow, std::vector<device_info>& infos,const std::wstring& idd) | |
148 | + { | |
149 | + | |
150 | + // 対象デバイスを列挙する | |
151 | + task<DeviceInformationCollection^> t((DeviceInformation::FindAllAsync(data_flow))); | |
152 | + t.wait(); | |
153 | + DeviceInformationCollection^ collection = t.get(); | |
154 | + int current_index = 0; | |
155 | + bool found = false; | |
156 | + Platform::String^ default_id = ref new Platform::String(); | |
157 | + switch(data_flow) | |
158 | + { | |
159 | + case Windows::Devices::Enumeration::DeviceClass::AudioRender: | |
160 | + default_id = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default); | |
161 | + break; | |
162 | + case Windows::Devices::Enumeration::DeviceClass::AudioCapture: | |
163 | + default_id = MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default); | |
164 | + break; | |
165 | + } | |
166 | + | |
167 | + | |
168 | + for(int i = 0 ,end = collection->Size;i < end;++i) | |
169 | + { | |
170 | + DeviceInformation^ info = collection->GetAt(i); | |
171 | + infos.push_back(device_info(info)); | |
172 | + if(info->Id == default_id) | |
173 | + { | |
174 | + infos[i].is_default_ = true; | |
175 | + } | |
176 | + | |
177 | + if(idd == wstring(info->Id->Data()) ) | |
178 | + { | |
179 | + infos[i].is_selected_ = true; | |
180 | + current_index = i; | |
181 | + found = true; | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + if(!found) | |
186 | + { | |
187 | + for(int i = 0,end = infos.size();i < end;++i) | |
188 | + { | |
189 | + if(infos[i].is_default_) | |
190 | + { | |
191 | + current_index = i; | |
192 | + infos[i].is_selected_ = true; | |
193 | + } | |
194 | + } | |
195 | + | |
196 | + } | |
197 | + return current_index; | |
198 | + } | |
199 | + | |
200 | + wasapi_device_manager::~wasapi_device_manager() | |
201 | + { | |
202 | + // stop_watching(); | |
203 | + } | |
204 | + | |
205 | + wasapi_device_manager::device_info::device_info | |
206 | + (DeviceInformation^ info) | |
207 | + : id_(info->Id->Data()), | |
208 | + name_(info->Name->Data()), | |
209 | + display_name_(dynamic_cast<String^>(info->Properties->Lookup(L"System.ItemNameDisplay"))->Data()), | |
210 | + is_enabled_(info->IsEnabled),is_selected_(false),is_default_(info->IsDefault) | |
211 | + { | |
212 | + boost::filesystem::wpath | |
213 | + config_path(wasapi_device_manager::base_directory() + L"\\" + Windows::Foundation::Uri::EscapeComponent(info->Id)->Data() + L".xml"); | |
214 | + if(boost::filesystem::exists(config_path)) | |
215 | + { | |
216 | + try{ | |
217 | + boost::filesystem::wifstream ifile(config_path); | |
218 | + boost::archive::xml_wiarchive ar(ifile); | |
219 | + ar >> BOOST_SERIALIZATION_NVP(params); | |
220 | + } catch (...) | |
221 | + { | |
222 | + // ファイル読み込みに問題がある場合はファイルを消す。 | |
223 | + boost::filesystem::remove(config_path); | |
224 | + } | |
225 | + } | |
448 | 226 | #ifdef _DEBUG |
449 | - wdout << L"================================================" << std::endl; | |
450 | - wdout << id_ << L"\n" << display_name_ << std::endl; | |
451 | - wdout << params.latency << std::endl; | |
452 | - wdout << L"================================================" << std::endl; | |
227 | + wdout << L"================================================" << std::endl; | |
228 | + wdout << id_ << L"\n" << display_name_ << std::endl; | |
229 | + wdout << params.latency << std::endl; | |
230 | + wdout << L"================================================" << std::endl; | |
453 | 231 | #endif |
454 | 232 | |
455 | - } | |
456 | - | |
457 | - wasapi_device_manager::device_info::~device_info() | |
458 | - { | |
459 | - try { | |
460 | - boost::filesystem::wpath | |
461 | - config_path(wasapi_device_manager::base_directory() + L"\\" + id_ + L".xml"); | |
462 | - boost::filesystem::wofstream ofile(config_path,std::ios_base::out | ios_base::trunc); | |
463 | - boost::archive::xml_woarchive ar(ofile); | |
464 | - ar << BOOST_SERIALIZATION_NVP(params); | |
465 | - } catch(...) | |
466 | - { | |
467 | - | |
468 | - } | |
469 | - } | |
470 | - | |
471 | - void wasapi_device_manager::output_added(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformation^ deviceInfo) | |
472 | - { | |
473 | - std::vector<device_info> * infos = nullptr; | |
233 | + } | |
234 | + | |
235 | + void wasapi_device_manager::stop_watching() | |
236 | + { | |
237 | + input_watcher_adapter_->stop(); | |
238 | + output_watcher_adapter_->stop(); | |
239 | + } | |
240 | + | |
241 | + void wasapi_device_manager::save_params() | |
242 | + { | |
243 | + // watcherの停止 | |
244 | + // stop_watching(); | |
245 | + | |
246 | + // 設定の保存 | |
247 | + try{ | |
248 | + boost::filesystem::wpath config_path(config_path_); | |
249 | + boost::filesystem::wofstream f(config_path,std::ios_base::out | std::ios_base::trunc); | |
250 | + boost::archive::xml_woarchive ar(f); | |
251 | + ar & boost::serialization::make_nvp("output_device_id",current_output_device().id_); | |
252 | + ar & boost::serialization::make_nvp("input_device_id" ,current_input_device().id_); | |
253 | + }catch(...) { | |
254 | + | |
255 | + } | |
256 | + | |
257 | + // 出力デバイスパラメータの保存 | |
258 | + for(device_info& inf : output_device_infos_) | |
259 | + { | |
260 | + | |
261 | + try { | |
262 | + boost::filesystem::wpath | |
263 | + config_path(wasapi_device_manager::base_directory() + L"\\" + Windows::Foundation::Uri::EscapeComponent(ref new Platform::String(inf.id_.c_str()))->Data() + L".xml"); | |
264 | + boost::filesystem::wofstream ofile(config_path,std::ios_base::out | ios_base::trunc); | |
265 | + boost::archive::xml_woarchive ar(ofile); | |
266 | + ar << BOOST_SERIALIZATION_NVP(inf.params); | |
267 | + } catch(...) | |
268 | + { | |
269 | + | |
270 | + } | |
271 | + } | |
272 | + | |
273 | + // 入力デバイスパラメータの保存 | |
274 | + for(device_info& inf : input_device_infos_) | |
275 | + { | |
276 | + | |
277 | + try { | |
278 | + boost::filesystem::wpath | |
279 | + config_path(wasapi_device_manager::base_directory() + L"\\" + Windows::Foundation::Uri::EscapeComponent(ref new Platform::String(inf.id_.c_str()))->Data() + L".xml"); | |
280 | + boost::filesystem::wofstream ofile(config_path,std::ios_base::out | ios_base::trunc); | |
281 | + boost::archive::xml_woarchive ar(ofile); | |
282 | + ar << BOOST_SERIALIZATION_NVP(inf.params); | |
283 | + } catch(...) | |
284 | + { | |
285 | + | |
286 | + } | |
287 | + } | |
288 | + | |
289 | + } | |
290 | + | |
291 | + wasapi_device_manager::device_info::~device_info() | |
292 | + { | |
293 | + } | |
294 | + | |
295 | + void wasapi_device_manager::output_added(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformation^ deviceInfo) | |
296 | + { | |
297 | + device_info info(deviceInfo); | |
298 | + | |
299 | + IAudioClient2Ptr c; | |
300 | + // オーディオクライアントを取得 | |
301 | + { | |
302 | + ComPtr<IActivateAudioInterfaceAsyncOperation> asyncOpPtr; | |
303 | + ComPtr<ActivateAudioInterfaceCompletionHandler> handler(Make<ActivateAudioInterfaceCompletionHandler>()); | |
304 | + HRESULT hr = ActivateAudioInterfaceAsync(info.id_.c_str(),__uuidof(IAudioClient2),nullptr,handler.Get(),asyncOpPtr.GetAddressOf()); | |
305 | + if(SUCCEEDED(hr)){ | |
306 | + handler->wait(); | |
307 | + if(handler->ResultCode() == S_OK) | |
308 | + { | |
309 | + c = handler->AudioClient(); | |
310 | + } else { | |
311 | + throw win32_error_exception(handler->ResultCode()); | |
312 | + } | |
313 | + } else { | |
314 | + throw win32_error_exception(handler->ResultCode()); | |
315 | + } | |
316 | + } | |
317 | + c->GetDevicePeriod(&(info.latency_default_),&(info.latency_minimum_)); | |
318 | + if(info.params.latency == 0 | |
319 | + || info.params.latency < info.latency_minimum_ ) | |
320 | + { | |
321 | + info.params.latency = info.latency_default_; | |
322 | + } | |
323 | + | |
474 | 324 | #ifdef _DEBUG |
475 | -// if(deviceInfo->IsEnabled){ | |
476 | - wdout << deviceInfo->Name->Data() << std::endl; | |
477 | - | |
478 | -// auto i = deviceInfo->Properties->First(); | |
479 | -// while(i->HasCurrent) | |
480 | -// { | |
481 | -//// wdout << iCurrent->Key->Data() << L"," << i->Current->Value->ToString()->Data() << std::endl; | |
482 | -// wdout << i-> | |
483 | -// i->MoveNext(); | |
484 | -// } | |
485 | -// } | |
325 | + wdout << info.name_ << endl; | |
326 | + wdout << boost::wformat(L"latency default:%d min:%d") % info.latency_default_ % info.latency_minimum_ << endl; | |
327 | +#endif | |
328 | + for(int bits = 0;bits < NUM_SAMPLE_BITS;++bits) | |
329 | + { | |
330 | + for(int channel = 1;channel < 3;++channel) | |
331 | + { | |
332 | + for(int rate = 0;rate < NUM_SAMPLE_RATE;++rate) | |
333 | + { | |
334 | + sf::co_task_memory<WAVEFORMATEXTENSIBLE> a,a1; | |
335 | + WAVEFORMATEXTENSIBLE f; | |
336 | + | |
337 | + // make_wave_fomat(f,sample_rates[rate],channel,sample_bits[bits]); | |
338 | + if(sample_bits[bits].valid_bits_per_sample == WAVE_FORMAT_IEEE_FLOAT) | |
339 | + { | |
340 | + bits_pair b ={sample_bits[bits].bits_per_sample,sample_bits[bits].bits_per_sample}; | |
341 | + make_wave_format(f,sample_rates[rate],channel,b,WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); | |
342 | + } else { | |
343 | + make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_PCM); | |
344 | + } | |
345 | + | |
346 | + // 排他モード | |
347 | + HRESULT hr = c->IsFormatSupported( | |
348 | + AUDCLNT_SHAREMODE_EXCLUSIVE,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a)); | |
349 | + if(hr == S_OK){ | |
350 | + info.support_formats_[AUDCLNT_SHAREMODE_EXCLUSIVE][ sample_bits[bits].bits_per_sample ][sample_bits[bits].valid_bits_per_sample][channel][sample_rates[rate]] = 0; | |
351 | +#ifdef _DEBUG | |
352 | + wdout << boost::wformat(L"|exc |bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") % sample_bits[bits].bits_per_sample % sample_bits[bits].valid_bits_per_sample % channel % sample_rates[rate] % (hr == S_OK?L"OK":L"NG") << endl; | |
353 | +#endif } | |
354 | + | |
355 | + // make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE); | |
356 | + // 共有モード | |
357 | + hr = c->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a1)); | |
358 | + if(hr == S_OK){ | |
359 | + info | |
360 | + .support_formats_ | |
361 | + [AUDCLNT_SHAREMODE_SHARED] | |
362 | + [ sample_bits[bits].bits_per_sample ] | |
363 | + [sample_bits[bits].valid_bits_per_sample] | |
364 | + [channel][sample_rates[rate]] | |
365 | + = 0; | |
366 | +#ifdef _DEBUG | |
367 | + wdout << boost::wformat(L"|share|bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") | |
368 | + % sample_bits[bits].bits_per_sample | |
369 | + % sample_bits[bits].valid_bits_per_sample | |
370 | + % channel % sample_rates[rate] | |
371 | + % (hr == S_OK?L"OK":L"NG") << endl; | |
372 | + | |
373 | +#endif | |
374 | + } | |
375 | + } | |
376 | + } | |
377 | + } | |
378 | +#ifdef _DEBUG | |
379 | + wdout << "-------------------------------" << std::endl; | |
486 | 380 | #endif |
487 | - } | |
381 | + } | |
382 | + | |
383 | + if(output_id_ == deviceInfo->Id->Data()) | |
384 | + { | |
385 | + info.is_selected_ = true; | |
386 | + } | |
387 | + if(default_output_id_ == deviceInfo->Id->Data()) | |
388 | + { | |
389 | + info.is_default_ = true; | |
390 | + } | |
391 | + output_device_infos_.push_back(info); | |
488 | 392 | |
489 | - void wasapi_device_manager::output_enumeration_completed(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
490 | - { | |
491 | - } | |
393 | +#ifdef _DEBUG | |
394 | + wdout << deviceInfo->Name->Data() << std::endl; | |
395 | +#endif | |
396 | +} | |
397 | + | |
398 | +void wasapi_device_manager::output_enumeration_completed(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
399 | +{ | |
400 | + | |
401 | + for(int i = 0;i < output_device_infos_.size();++i) | |
402 | + { | |
403 | + device_info& inf(output_device_infos_[i]); | |
404 | + if(inf.is_selected_ && inf.is_enabled_) | |
405 | + { | |
406 | + output_device_index_ = i; | |
407 | + } | |
408 | + } | |
409 | + | |
410 | + if(output_device_index_ == -1) | |
411 | + { | |
412 | + for(int i = 0;i < output_device_infos_.size();++i) | |
413 | + { | |
414 | + device_info& inf(output_device_infos_[i]); | |
415 | + if(inf.is_default_) | |
416 | + { | |
417 | + output_device_index_ = i; | |
418 | + inf.is_selected_ = true; | |
419 | + } | |
420 | + } | |
421 | + } | |
422 | + | |
423 | + output_enum_completed_ = true; | |
424 | +} | |
425 | + | |
426 | +void wasapi_device_manager::output_updated(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
427 | +{ | |
428 | +} | |
429 | + | |
430 | +void wasapi_device_manager::output_removed(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
431 | +{ | |
432 | +} | |
433 | + | |
434 | +void wasapi_device_manager::output_stopped(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
435 | +{ | |
436 | +} | |
437 | + | |
438 | +void wasapi_device_manager::input_added(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformation^ deviceInfo) | |
439 | +{ | |
440 | + device_info info(deviceInfo); | |
441 | + IAudioClient2Ptr c; | |
442 | + // オーディオクライアントを取得 | |
443 | + // THROW_IF_ERR(ActivateAudioInterface(info.id_.c_str(),__uuidof(IAudioClient2),&c) ); | |
444 | + { | |
445 | + ComPtr<IActivateAudioInterfaceAsyncOperation> asyncOpPtr; | |
446 | +// IActivateAudioInterfaceAsyncOperation* asyncOp; | |
447 | + ComPtr<ActivateAudioInterfaceCompletionHandler> handler(Make<ActivateAudioInterfaceCompletionHandler>()); | |
448 | + HRESULT hr = ActivateAudioInterfaceAsync(info.id_.c_str(),__uuidof(IAudioClient2),nullptr,handler.Get(),asyncOpPtr.GetAddressOf()); | |
449 | +// asyncOpPtr.Attach(asyncOp); | |
450 | + if(SUCCEEDED(hr)){ | |
451 | + handler->wait(); | |
452 | + if(handler->ResultCode() == S_OK) | |
453 | + { | |
454 | + c = handler->AudioClient(); | |
455 | + } else { | |
456 | + throw win32_error_exception(handler->ResultCode()); | |
457 | + } | |
458 | + } else { | |
459 | + throw win32_error_exception(handler->ResultCode()); | |
460 | + } | |
461 | + } | |
462 | + c->GetDevicePeriod(&(info.latency_default_),&(info.latency_minimum_)); | |
463 | + if(info.params.latency == 0 || info.params.latency < info.latency_minimum_ ){ | |
464 | + info.params.latency = info.latency_default_; | |
465 | + } | |
466 | +#ifdef _DEBUG | |
467 | + wdout << info.display_name_ << endl; | |
468 | + wdout << boost::wformat(L"latency default:%d min:%d") % info.latency_default_ % info.latency_minimum_ << endl; | |
469 | +#endif | |
470 | + for(int bits = 0;bits < NUM_SAMPLE_BITS;++bits) | |
471 | + { | |
472 | + for(int channel = 1;channel < 3;++channel) | |
473 | + { | |
474 | + for(int rate = 0;rate < NUM_SAMPLE_RATE;++rate) | |
475 | + { | |
476 | + sf::co_task_memory<WAVEFORMATEXTENSIBLE> a,a1; | |
477 | + WAVEFORMATEXTENSIBLE f; | |
478 | + | |
479 | + // make_wave_fomat(f,sample_rates[rate],channel,sample_bits[bits]); | |
480 | + if(sample_bits[bits].valid_bits_per_sample == WAVE_FORMAT_IEEE_FLOAT) | |
481 | + { | |
482 | + bits_pair b ={sample_bits[bits].bits_per_sample,sample_bits[bits].bits_per_sample}; | |
483 | + make_wave_format(f,sample_rates[rate],channel,b,WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_IEEE_FLOAT); | |
484 | + } else { | |
485 | + make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE,KSDATAFORMAT_SUBTYPE_PCM); | |
486 | + } | |
487 | + | |
488 | + // 排他モード | |
489 | + HRESULT hr = c->IsFormatSupported( | |
490 | + AUDCLNT_SHAREMODE_EXCLUSIVE,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a)); | |
491 | + if(hr == S_OK){ | |
492 | + info | |
493 | + .support_formats_ | |
494 | + [AUDCLNT_SHAREMODE_EXCLUSIVE] | |
495 | + [ sample_bits[bits].bits_per_sample ] | |
496 | + [sample_bits[bits].valid_bits_per_sample] | |
497 | + [channel] | |
498 | + [sample_rates[rate]] = 0; | |
499 | +#ifdef _DEBUG | |
500 | + wdout << boost::wformat(L"|exc |bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") | |
501 | + % sample_bits[bits].bits_per_sample | |
502 | + % sample_bits[bits].valid_bits_per_sample | |
503 | + % channel % sample_rates[rate] | |
504 | + % (hr == S_OK?L"OK":L"NG") << endl; | |
505 | +#endif } | |
506 | + | |
507 | + // make_wave_format(f,sample_rates[rate],channel,sample_bits[bits],WAVE_FORMAT_EXTENSIBLE); | |
508 | + // 共有モード | |
509 | + hr = c->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,reinterpret_cast<WAVEFORMATEX*>(&f),reinterpret_cast<WAVEFORMATEX**>(&a1)); | |
510 | + if(hr == S_OK){ | |
511 | + info. | |
512 | + support_formats_ | |
513 | + [AUDCLNT_SHAREMODE_SHARED] | |
514 | + [sample_bits[bits].bits_per_sample ] | |
515 | + [sample_bits[bits].valid_bits_per_sample] | |
516 | + [channel] | |
517 | + [sample_rates[rate]] = 0; | |
518 | +#ifdef _DEBUG | |
519 | + wdout << boost::wformat(L"|share|bits:%02d|vbits:%02d|channel:%02d|rate:%06d|%s|") | |
520 | + % sample_bits[bits].bits_per_sample | |
521 | + % sample_bits[bits].valid_bits_per_sample | |
522 | + % channel | |
523 | + % sample_rates[rate] | |
524 | + % (hr == S_OK?L"OK":L"NG") << endl; | |
492 | 525 | |
493 | - void wasapi_device_manager::output_updated(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
494 | - { | |
495 | - } | |
526 | +#endif | |
527 | + } | |
528 | + } | |
529 | + } | |
530 | + } | |
531 | +#ifdef _DEBUG | |
532 | + wdout << "-------------------------------" << std::endl; | |
533 | +#endif | |
534 | +} | |
496 | 535 | |
497 | - void wasapi_device_manager::output_removed(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
498 | - { | |
499 | - } | |
536 | +if(input_id_ == deviceInfo->Id->Data()) | |
537 | +{ | |
538 | + info.is_selected_ = true; | |
539 | +} | |
540 | +if(default_input_id_ == deviceInfo->Id->Data()) | |
541 | +{ | |
542 | + info.is_default_ = true; | |
543 | +} | |
500 | 544 | |
501 | - void wasapi_device_manager::output_stopped(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
502 | - { | |
503 | - } | |
545 | +input_device_infos_.push_back(info); | |
504 | 546 | |
505 | - void wasapi_device_manager::input_added(Windows::Devices::Enumeration::DeviceWatcher^ sender, Windows::Devices::Enumeration::DeviceInformation^ deviceInfo) | |
506 | - { | |
507 | - std::vector<device_info> * infos = nullptr; | |
508 | 547 | #ifdef _DEBUG |
509 | 548 | // if(deviceInfo->IsEnabled){ |
510 | - wdout << deviceInfo->Name->Data() << std::endl; | |
511 | - | |
549 | +wdout << deviceInfo->Name->Data() << std::endl; | |
550 | + | |
512 | 551 | // auto i = deviceInfo->Properties->First(); |
513 | 552 | // while(i->HasCurrent) |
514 | 553 | // { |
@@ -518,21 +557,44 @@ namespace sf { | ||
518 | 557 | // } |
519 | 558 | // } |
520 | 559 | #endif |
521 | - } | |
522 | - | |
523 | - void wasapi_device_manager::input_enumeration_completed(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
524 | - { | |
525 | - } | |
526 | - | |
527 | - void wasapi_device_manager::input_updated(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
528 | - { | |
529 | - } | |
530 | - | |
531 | - void wasapi_device_manager::input_removed(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
532 | - { | |
533 | - } | |
534 | - | |
535 | - void wasapi_device_manager::input_stopped(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
536 | - { | |
537 | - } | |
560 | + } | |
561 | + | |
562 | + void wasapi_device_manager::input_enumeration_completed(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
563 | + { | |
564 | + | |
565 | + for(int i = 0;i < input_device_infos_.size();++i) | |
566 | + { | |
567 | + device_info& inf(input_device_infos_[i]); | |
568 | + if(inf.is_selected_ && inf.is_enabled_) | |
569 | + { | |
570 | + input_device_index_ = i; | |
571 | + } | |
572 | + } | |
573 | + | |
574 | + if(input_device_index_ == -1) | |
575 | + { | |
576 | + for(int i = 0;i < input_device_infos_.size();++i) | |
577 | + { | |
578 | + device_info& inf(input_device_infos_[i]); | |
579 | + if(inf.is_default_) | |
580 | + { | |
581 | + input_device_index_ = i; | |
582 | + inf.is_selected_ = true; | |
583 | + } | |
584 | + } | |
585 | + } | |
586 | + input_enum_completed_ = true; | |
587 | + } | |
588 | + | |
589 | + void wasapi_device_manager::input_updated(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
590 | + { | |
591 | + } | |
592 | + | |
593 | + void wasapi_device_manager::input_removed(en::DeviceWatcher^ sender, en::DeviceInformationUpdate^ deviceInfo) | |
594 | + { | |
595 | + } | |
596 | + | |
597 | + void wasapi_device_manager::input_stopped(en::DeviceWatcher^ sender, Platform::Object^ obj) | |
598 | + { | |
599 | + } | |
538 | 600 | } |
\ No newline at end of file |