c - 通过pthread create调用时,通过alsa输出声音的功能不起作用:无声音,CPU使用率100%

标签 c linux audio pthreads libalsa

我有一个程序,该程序通过套接字接收消息,并根据消息开始或停止播放某些声音文件。为了使“停止”消息起作用,我需要从单独的线程播放声音。我的解决方案是使用通过pthread_create()调用的函数中的alsa播放声音,并在收到停止消息后使用pthread_cancel()结束线程。播放声音的功能称为play_sound(void * args);
这是有效的方法:

struct args *args;

args->fp     = fopen("path/to/soundfile.wav", "r");
args->volume = 1;

play_sound((void *) args);
但是,当我尝试从新线程中运行该函数时,两个线程都没有声音并且CPU使用率达到100%:
struct args *args;
int sound_thread;

args->fp     = fopen("path/to/soundfile.wav", "r");
args->volume = 1;

pthread_create(&sound_thread, NULL, (void *) play_sound, (void *) args);
我什至不知道从哪里开始故障排除。
我的代码如下所示:
#include <alsa/asoundlib.h>
#include <alsa/mixer.h>
#include <stdbool.h>
#include <pthread.h>

#include "server.h"
#include "sound.h"
//#include "log.h" 



int sound_thread;




struct args {
    FILE *fp;
    float volume;
};




void init_sound ()
{
    sound_thread = -1;
}




void stop_sound ()
{
    if (sound_thread != -1) {
        pthread_cancel(sound_thread);
        keep_playing = false;
        sound_thread = -1;
    }
}




void dispatch_sound (FILE *fp, float volume)
{

    // this function serves to create a new thread for the
    // sound to be played from. This is what's giving me
    // headaches.


    if (sound_thread != -1) {
        stop_sound();
    }

    struct args *args = (struct args *) malloc(sizeof(struct args));

    args->fp     = fp;
    args->volume = volume;

    if (pthread_create(&sound_thread, NULL, (void *) play_sound, args) != 0) 
        sound_thread = -1;
    }
}




bool play_sound (void *args)
{

    // This function actually plays the sound using functions
    // from the alsa lib. it works when invoked regularly without
    // threading.


    keep_playing = true;

    FILE                *fp;
    int                 volume;
    bool                success;
    unsigned int        samplerate;
    int                 bufsz;
    char                *buf;
    snd_pcm_t           *pcm;
    snd_pcm_hw_params_t *params;
    snd_pcm_uframes_t   frames;

    samplerate = SAMPLERATE;


    fp     = ((struct args *) args)->fp;
    volume = ((struct args *) args)->volume;

    // volume is not actually used right now, since I took out
    // the function that sets the volume before playing the
    // audio in order to make it easier to pinpoint the issue.


    if (snd_pcm_open(&pcm, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
        success = false;
    }


    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(pcm, params);

    if (snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        success = false;
    }

    if (snd_pcm_hw_params_set_format(pcm, params, SND_PCM_FORMAT_S16_LE) < 0) {
        success = false;
    }

    if (snd_pcm_hw_params_set_channels(pcm, params, CHANNELS) < 0) {
        success = false;
    }

    if (snd_pcm_hw_params_set_rate_near(pcm, params, &samplerate, 0) < 0) {
        success = false;
    }´

    if (snd_pcm_hw_params(pcm, params) < 0) {
        success = false;
    }


    snd_pcm_hw_params_get_period_size(params, &frames, 0);
    bufsz = frames * CHANNELS * SAMPLE_SIZE;
    buf   = (char *) malloc(bufsz);


    while (keep_playing) {
        while (fread(buf, bufsz, 1, fp) != 0 && keep_playing) {

            int err;

            if ((err = snd_pcm_writei(pcm, buf, frames)) == -EPIPE) {
                snd_pcm_prepare(pcm);
            }
        }

        rewind(fp);
    }


    snd_pcm_drain(pcm);
    snd_pcm_close(pcm);
    free(buf);


    return success;
}

最佳答案

在pthread_cancel的手册页中:

On Linux, cancellation is implemented using signals. Under the NPTL threading implementation, the first real-time signal (i.e., signal 32) is used for this purpose. On LinuxThreads, the second real-time signal is used, if real-time signals are available, otherwise SIGUSR2 is used.


在while(keep_playing)循环中,您产生的线程不足以处理取消信号;在您的主线程中;您没有在等待取消请求的结果,因此两个线程都占用了CPU。
在调用pthread_cancel之后重新开始播放声音和pthread_join()之前,稍作延迟即可解决您的问题。

关于c - 通过pthread create调用时,通过alsa输出声音的功能不起作用:无声音,CPU使用率100%,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62897483/

相关文章:

linux - 无法从 Windows ssh 到 Linux 计算机,出现错误 ssh : connect to host "Ip Address" port 22: Bad file number

linux - 创建纹理时 MonoGame 抛出 MonoGameGLException (InvalidEnum) 错误

android - Android:使用音频文件填充listview并打开新 Activity

C-Fortran 混合编程

html - 使用 perl 处理 C 源代码的 Doxygen HTML 输出——如何从 href 加载文件?

c - 如何在 Linux 上使用 C 语言在多线程中使用互斥量

java - Jitsi - 在通话期间播放 WAV 文件 - 如果可能,与音频混合

JavaScript 测验安全性

c - 将 char 设置为所有真位

c - 打印带空格的函数入口和导出