|
|
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); ! 50: monitor->func = ToMonitorCallback(&HostSoundDevice::MonitorUpdate); ! 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 ! 333: HostSoundDevice::MonitorUpdate(Monitor *, TextScreen& screen) ! 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行はドライバ依存情報 ! 342: driver->MonitorUpdateMD(screen, 1); ! 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.