|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2025 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // サウンドのホストデバイス
9: //
10:
11: // 再生時のフロー
12: //
13: // Sound Thread : Host thread
14: //
15: // HostSoundDevice::Play() : HostDevice::ThreadRun
16: // |
17: // +-------------->| queue |----+ … 送信キューに追加し
18: // +-------------->| pipe |----+ … パイプでホストスレッドに通知
19: // | |
20: // <-+ : v
21: // --- kevent
22: // : |
23: // HostSoundDevice::Write()
24: // : |
25: // SoundDriver*::Write()
26: // : |
27: // +------> Playback in the real world
28:
29: #include "hostsound.h"
30: #include "config.h"
31: #include "sound.h"
32: #if defined(HAVE_HOSTSOUND_ALSA)
33: #include "sounddriver_alsa.h"
34: #endif
35: #if defined(HAVE_HOSTSOUND_NETBSD)
36: #include "sounddriver_netbsd.h"
37: #endif
38: #if defined(HAVE_HOSTSOUND_SNDIO)
39: #include "sounddriver_sndio.h"
40: #endif
41: #include "sounddriver_none.h"
42: #include "sounddriver_wav.h"
43: #include "uimessage.h"
44:
45: // コンストラクタ
46: HostSoundDevice::HostSoundDevice(Device *parent_)
47: : inherited(parent_, OBJ_HOSTSOUND, ""/*portname*/)
48: {
49: monitor = gMonitorManager->Regist(ID_MONITOR_HOSTSOUND, this);
1.1.1.2 ! root 50: monitor->SetCallback(&HostSoundDevice::MonitorScreen);
1.1 root 51: monitor->SetSize(48, 6);
52: }
53:
54: // デストラクタ
55: HostSoundDevice::~HostSoundDevice()
56: {
57: }
58:
59: // ログレベル設定
60: void
61: HostSoundDevice::SetLogLevel(int loglevel_)
62: {
63: inherited::SetLogLevel(loglevel_);
64:
65: RWLockGuard_Read guard(driverlock);
66: if ((bool)driver) {
67: driver->SetLogLevel(loglevel_);
68: }
69: }
70:
71: // 動的コンストラクションその2
72: bool
73: HostSoundDevice::Create2()
74: {
75: if (inherited::Create2() == false) {
76: return false;
77: }
78:
79: // SelectDriver() は SoundRenderer::Reconfig() から呼ばれるので、
80: // ここでは不要。
81:
82: return true;
83: }
84:
85: // ドライバ(再)選択。
86: // エラーが起きた場合、
87: // 起動時なら、warn() 等で表示して false を返す(終了する)。
88: // 実行中なら、warn() 等で表示してもいいが、必ず None にフォールバックして
89: // true を返すこと。
90: bool
91: HostSoundDevice::SelectDriver(bool startup)
92: {
93: auto sound = dynamic_cast<SoundRenderer *>(parent);
94: freq = sound->GetOutFrequency();
95: bytes_per_blk = sound->GetOutBytesPerBlk();
96:
97: RWLockGuard_Write guard(driverlock);
98:
99: driver.reset();
100: errmsg.clear();
101:
102: // ドライバはここで選択。
103: const ConfigItem& item = gConfig->Find("hostsound-driver");
104: std::string type = item.AsString();
105:
106: // auto は環境による。
107: if (type == "auto") {
108: #if defined(HAVE_HOSTSOUND_NETBSD)
109: type = "netbsd";
110: #elif defined(HAVE_HOSTSOUND_SNDIO)
111: type = "sndio";
112: #elif defined(HAVE_HOSTSOUND_ALSA)
113: type = "alsa";
114: #else
115: type = "none";
116: #endif
117: }
118:
119: enum {
120: ERR_CONFIG, // 設定でのエラー
121: ERR_INVALID, // 知らないドライバ
122: ERR_NOTSUPP, // コンパイルされてない
123: } reason = ERR_CONFIG;
124:
125: if (type == "none") {
126: CreateNone();
127:
128: } else if (type == "wav") {
129: CreateWav();
130:
131: } else if (type == "netbsd") {
132: #if defined(HAVE_HOSTSOUND_NETBSD)
133: CreateNetBSD();
134: #else
135: reason = ERR_NOTSUPP;
136: #endif
137:
138: } else if (type == "sndio") {
139: #if defined(HAVE_HOSTSOUND_SNDIO)
140: CreateSndIO();
141: #else
142: reason = ERR_NOTSUPP;
143: #endif
144:
145: } else if (type == "alsa") {
146: #if defined(HAVE_HOSTSOUND_ALSA)
147: CreateALSA();
148: #else
149: reason = ERR_NOTSUPP;
150: #endif
151:
152: } else {
153: // 知らないドライバ種別
154: reason = ERR_INVALID;
155: }
156:
157: if ((bool)driver == false) {
158: // 指定のドライバが使えなかった場合、
159: // o 起動時ならエラー終了する。
160: // o 実行中なら none にフォールバックする。
161: if (startup) {
162: switch (reason) {
163: case ERR_INVALID:
164: item.Err("Invalid driver name");
165: break;
166: case ERR_CONFIG:
167: item.Err("Could not configure the driver");
168: warnx("(See details with option -C -Lhostsound=1)");
169: break;
170: case ERR_NOTSUPP:
171: item.Err("HostSound driver %s not compiled", type.c_str());
172: break;
173: default:
174: assert(false);
175: }
176: return false;
177: } else {
178: gMainApp.GetUIMessage()->Post(UIMessage::HOSTSOUND_FAILED);
179:
180: CreateNone();
181: }
182: }
183: assert((bool)driver);
184:
185: // ドライバ名は Capitalize だがログはほぼ小文字なので雰囲気を揃える…
186: putmsg(1, "selected host driver: %s",
187: string_tolower(driver->GetDriverName()).c_str());
188:
189: return true;
190: }
191:
192: // None ドライバを生成する。
193: // 戻り値はなく、成否は (bool)driver で判断する。
194: void
195: HostSoundDevice::CreateNone()
196: {
197: try {
198: driver.reset(new SoundDriverNone(this));
199: } catch (...) { }
200: if ((bool)driver) {
201: if (driver->InitDriver()) {
202: // 成功
203: return;
204: }
205: errmsg = driver->errmsg;
206: driver.reset();
207: }
208: }
209:
210: // Wav ドライバを生成する。
211: // 戻り値はなく、成否は (bool)driver で判断する。
212: void
213: HostSoundDevice::CreateWav()
214: {
215: try {
216: driver.reset(new SoundDriverWav(this));
217: } catch (...) { }
218: if ((bool)driver) {
219: if (driver->InitDriver()) {
220: // 成功
221: return;
222: }
223: errmsg = driver->errmsg;
224: driver.reset();
225: }
226: }
227:
228: #if defined(HAVE_HOSTSOUND_NETBSD)
229: // NetBSD ドライバを生成する。
230: // 戻り値はなく、成否は (bool)driver で判断する。
231: void
232: HostSoundDevice::CreateNetBSD()
233: {
234: try {
235: driver.reset(new SoundDriverNetBSD(this));
236: } catch (...) { }
237: if ((bool)driver) {
238: if (driver->InitDriver()) {
239: // 成功
240: return;
241: }
242: errmsg = driver->errmsg;
243: driver.reset();
244: }
245: }
246: #endif
247:
248: #if defined(HAVE_HOSTSOUND_SNDIO)
249: // sndio ドライバを生成する。
250: // 戻り値はなく、成否は (bool)driver で判断する。
251: void
252: HostSoundDevice::CreateSndIO()
253: {
254: try {
255: driver.reset(new SoundDriverSndIO(this));
256: } catch (...) { }
257: if ((bool)driver) {
258: if (driver->InitDriver()) {
259: // 成功
260: return;
261: }
262: errmsg = driver->errmsg;
263: driver.reset();
264: }
265: }
266: #endif
267:
268: #if defined(HAVE_HOSTSOUND_ALSA)
269: // ALSA ドライバを生成する。
270: // 戻り値はなく、成否は (bool)driver で判断する。
271: void
272: HostSoundDevice::CreateALSA()
273: {
274: try {
275: driver.reset(new SoundDriverALSA(this));
276: } catch (...) { }
277: if ((bool)driver) {
278: if (driver->InitDriver()) {
279: // 成功
280: return;
281: }
282: errmsg = driver->errmsg;
283: driver.reset();
284: }
285: }
286: #endif
287:
288: // サウンドスレッドからの再生(の指示) (サウンドスレッドで呼ばれる)。
289: bool
290: HostSoundDevice::Play(const int16 *blk)
291: {
292: playq.Enqueue(blk);
293:
294: // パイプで通知。
295: return WritePipe(PIPE_TX);
296: }
297:
298: // 外部への書き出し (再生)
299: void
300: HostSoundDevice::Write()
301: {
302: const int16 * const *blkp;
303:
304: RWLockGuard_Read guard(driverlock);
305: assert((bool)driver);
306:
307: // 再生リングバッファから1ブロック取り出す。
308: while ((blkp = playq.BeginRead()) != NULL) {
309: stat.write_blk++;
310: driver->Write(*blkp);
311: playq.EndRead();
312: }
313: }
314:
315: // 外部からの読み込み (録音)
316: // 未対応
317: int
318: HostSoundDevice::Read()
319: {
320: return 0;
321: }
322:
323: const std::string&
324: HostSoundDevice::GetDriverName()
325: {
326: RWLockGuard_Read guard(driverlock);
327: assert((bool)driver);
328: return driver->GetDriverName();
329: }
330:
331: // モニタ
332: void
1.1.1.2 ! root 333: HostSoundDevice::MonitorScreen(Monitor *, TextScreen& screen)
1.1 root 334: {
335: screen.Clear();
336:
337: {
338: RWLockGuard_Read gurad(driverlock);
339: screen.Print(0, 0, "HostSound Driver: %s",
340: driver->GetDriverName().c_str());
341: // 次の1行はドライバ依存情報
1.1.1.2 ! root 342: driver->MonitorScreenMD(screen, 1);
1.1 root 343: }
344:
345: screen.Print(0, 2, "Output Frequency: %u Hz", freq);
346:
347: int y = 4;
348: screen.Print(0, y++, "%-17s%13s %17s", "<Play>", "Blocks", "Bytes");
349: screen.Print(0, y++, "%-17s%13s %17s", "Write to host",
350: format_number(stat.write_blk).c_str(),
351: format_number(stat.write_blk * bytes_per_blk).c_str());
352: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.