libasound
を使用してALSA再生デバイスにランダムバイトを書き込む際に問題が発生しています。最終的に私の目標は、再生ストリームをネットワーク経由でルーティングし、リモートデバイスで再生できるようにすることです。ALSA再生デバイスへのバイトストリーミング
this questionのコードは、WAVファイルをメモリに読み込んで、snd_pcm_writei
経由でドライバに書き込みます。しかし、このコードが行うことと私がやろうとしていることとの間に重大な違いは、すべて私にすぐに利用可能なデータがないということです。私はそれが利用可能になるとデータをストリーミングするために探しています。私のニーズに合うように上記のサンプルコードを適応さ
は、私はこれで終わる:
#include <stdio.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
static snd_pcm_t *PlaybackHandle;
int init_playback(const char *device, int samplerate, int channels) {
int err;
printf("Init parameters: %s %d %d\n", device, samplerate, channels);
if((err = snd_pcm_open(&PlaybackHandle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Can't open audio %s: %s\n", device, snd_strerror(err));
return -1;
}
if ((err = snd_pcm_set_params(PlaybackHandle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, channels, samplerate, 1, 500000)) < 0) {
printf("Can't set sound parameters: %s\n", snd_strerror(err));
return -1;
}
return 0;
}
int play_bytes(const void *bytes, int len) {
snd_pcm_uframes_t frames, count;
snd_pcm_uframes_t bufsize, period_size;
frames = 0;
count = 0;
snd_pcm_prepare(PlaybackHandle);
snd_pcm_get_params(PlaybackHandle, &bufsize, &period_size);
printf("bufsize=%d\n", (int) bufsize);
do {
int remaining = len - count;
int buflen = remaining < bufsize ? remaining : bufsize;
frames = snd_pcm_writei(PlaybackHandle, bytes + count, buflen);
// If an error, try to recover from it
if (frames == -EPIPE) {
printf("EPIPE\n");
snd_pcm_prepare(PlaybackHandle);
}
if (frames < 0) {
printf("Recovering\n");
frames = snd_pcm_recover(PlaybackHandle, frames, 0);
}
if (frames < 0)
{
printf("Error playing wave: %s\n", snd_strerror(frames));
break;
}
// Update our pointer
count += frames;
//printf("count=%d len=%d\n", (int)count, len);
} while (count < len);
// Wait for playback to completely finish
if (count == len)
snd_pcm_drain(PlaybackHandle);
return 0;
}
int close_playback() {
snd_pcm_close(PlaybackHandle);
return 0;
}
int main(int argc, char **argv) {
if(argc < 1) {
printf("Usage: %s <WAV-file>\n", argv[0]);
return -1;
}
int fd;
unsigned long long len;
fd = open(argv[1], O_RDONLY);
// Find the length
len = lseek(fd, 0, SEEK_END);
// Skip the first 44 bytes (header)
lseek(fd, 44, SEEK_SET);
len -= 44;
char *data = malloc(len);
read(fd, data, len);
init_playback("default", 44100, 2);
play_bytes(data, len);
close_playback();
return 0;
}
このコードはgcc playback.c -o playback -lasound
してコンパイルすることができます。私が使用しているWAVファイルはhereです。
このコードスニペットを実行すると、bufsize
に基づいて着信データをチャンクすると、チャンクサイズに応じて再生中に繰り返されるオーディオの断片があります。チャンクサイズが大きいと、チャンクサイズが小さい場合よりも繰り返し回数が少なくなります。これをオーディオの仕組みと組み合わせると、各チャンクの最後に小さな断片が繰り返されていると思います。
私が使用するパラメータは以下の通りであった。
- サンプルレート:44100
- チャンネル:2
はなぜワンショット作業全体WAVファイルを送信するのですか?ドライバにオーディオデータのチャンクを送信し、正しく再生させるにはどうすればよいですか?
'snd_pcm_drain()'は、ストリームの最後でのみ使用します。 –
お元気ですか?私がやっていることのほとんどは、動作するサンプルコードと同じです。違いは、私は内部的にファイルの内容をチャンクして 'snd_pcm_write'を呼び出すのに対して、サンプルコードはファイルの内容全体を' snd_pcm_writei'に提示する点です。私のスニペットで 'snd_pcm_drain'をどこで呼び出すべきですか? –
質問を更新し、完全に動作するコードサンプルと、テストするために使用しているWAVファイルの1つを追加しました。私は "反復"を記述することは難しいと思うので、うまくいけば、これは助けになるだろう –