aboutsummaryrefslogtreecommitdiff
path: root/src/AudioPlayer.cpp
blob: 8d30ee688038d09a4df362f7f9de23a73e98e831 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "../include/AudioPlayer.hpp"

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#include <pulse/simple.h>
#include <pulse/error.h>

#define BUFSIZE 4096

namespace gsr {
    AudioPlayer::~AudioPlayer() {
        if(thread.joinable()) {
            stop_playing_audio = true;
            thread.join();
        }

        if(audio_file_fd > 0)
            close(audio_file_fd);
    }

    bool AudioPlayer::play(const char *filepath) {
        if(thread.joinable()) {
            stop_playing_audio = true;
            thread.join();
        }

        stop_playing_audio = false;
        audio_file_fd = open(filepath, O_RDONLY);
        if(audio_file_fd == -1)
            return false;

        thread = std::thread([this]() {
            const pa_sample_spec ss = {
                .format = PA_SAMPLE_S16LE,
                .rate = 48000,
                .channels = 2
            };

            pa_simple *s = NULL;
            int error;

            /* Create a new playback stream */
            if(!(s = pa_simple_new(NULL, "gsr-ui-audio-playback", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) {
                fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
                goto finish;
            }

            uint8_t buf[BUFSIZE];
            for(;;) {
                ssize_t r;

                if(stop_playing_audio)
                    goto finish;

                if((r = read(audio_file_fd, buf, sizeof(buf))) <= 0) {
                    if(r == 0) /* EOF */
                        break;

                    fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
                    goto finish;
                }

                if(pa_simple_write(s, buf, (size_t) r, &error) < 0) {
                    fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
                    goto finish;
                }
            }

            if(pa_simple_drain(s, &error) < 0) {
                fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
                goto finish;
            }

            finish:
            if(s)
                pa_simple_free(s);

            close(audio_file_fd);
            audio_file_fd = -1;
        });

        return true;
    }
}