皆さん、検証いただきありがとうございました。
ポップノイズなどお気付きの点がありましたらお知らせください。
今取り組んでいるのは『負荷を低減・平滑化していくとどんな音になるのか』というテーマとなります。
その実現手段として、セパレート構成の実装を進めています。
セパレート構成の実装にあたり、重要なポイントが二つあります。
一つは「カーネルのTCP/IPスタックをバイパス」すること。
もうひとつは「DMA転送バッファのスワップ」を実装することです。
再生負荷が低いRAMディスクからaplayで再生という事例で、再生までにどのような処理が行われるかを例示してみます。
RAM
⇨aplayバッファ
⇨ALSAバッファ
>> FIFO
矢印(⇨)はメモリ上でのデータのコピーを表します。このようなデータのコピーはメモリからレジスタへの読み込みとレジスタからメモリへの書き込みを組み合わせて実現されます。
最後のFIFOへのコピーはDMAで、CPUを使わないデータコピーです。
次に、v0.4系のセパレート構成を例示します。
ncatでデータを受け取り、パイプ経由でaplayで再生する方式です。
ソケットバッファ
⇨ncatバッファ
⇨カーネルバッファ
⇨aplayバッファ
⇨ALSAバッファ
>> FIFO
次はv1.0系でmpd再生する例です。
ソケットバッファ
⇨mpdバッファ
⇨xsinkバッファ
⇨ALSAバッファ
>> FIFO
今回のv1.0.8βでmpd再生する例がこちらです。
ソケットバッファ
⇨mpdバッファ
⇨xsinkバッファ
>> FIFO
セパレート構成の実装のために研究していたDMA転送バッファのスワップを応用して、データコピーを1ステップ削減することができました。
最終的なセパレート構成で目指しているのがこちらです。
ソケットバッファ
>> FIFO
ソケットバッファから直接FIFOにDMAしてしまうというシンプルなアイデアです。
メモリ上でのPCMデータのコピーはただの一度もありません。
低負荷を突き詰めていくとこの方式に収斂するだろうと思います。これ以上、処理を減らしようがないからです。
ネットワーク経由で受け取ったパケットのうち、PCMデータ以外は全てカーネルのTCP/IPスタックに渡します。(不要なパケットはこの段階でフィルタしてしまうことで、さらに負荷を下げることもできます。)
PCMデータの入ったソケットバッファはそのまま保持しておき、DMA転送が終わったソケットバッファと逐次交換していくことで連続再生します。
セパレート構成の実装に必要な2つの要素技術(カーネルバイパス・DMAバッファスワップ)は実用レベルになってきました。
引き続き、年内に試作版を公開できるよう進めたいと思います。