summaryrefslogtreecommitdiffstats
path: root/src/AlsaInput.h
blob: eb02ec1a0c4bb076d2167216232fcb172c5ed1bb (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* ------------------------------------------------------------------
 * Copyright (C) 2011 Martin Storsjo
 * Copyright (C) 2013,2014 Matthias P. Braendli
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */

#ifndef __ALSA_H_
#define __ALSA_H_
#include <cstdio>
#include <string>

#include <alsa/asoundlib.h>
#include <boost/thread/thread.hpp>

#include "SampleQueue.h"

using namespace std;

// 16 bits per sample is fine for now
#define BYTES_PER_SAMPLE 2

// How many samples we insert into the queue each call
#define NUM_SAMPLES_PER_CALL 10 // 10 samples @ 32kHz = 3.125ms

class AlsaInput
{
    public:
        AlsaInput(const string& alsa_dev,
                unsigned int channels,
                unsigned int rate) :
            m_alsa_dev(alsa_dev),
            m_channels(channels),
            m_rate(rate),
            m_alsa_handle(NULL) { }

        ~AlsaInput() {

            if (m_alsa_handle) {
                snd_pcm_abort(m_alsa_handle);
                m_alsa_handle = NULL;
            }
        }

        /* Prepare the audio input */
        int prepare();

        virtual void start() = 0;

    protected:
        size_t m_read(uint8_t* buf, snd_pcm_uframes_t length);

        string m_alsa_dev;
        unsigned int m_channels;
        unsigned int m_rate;

        snd_pcm_t *m_alsa_handle;

    private:
        AlsaInput(const AlsaInput& other) {}
};

class AlsaInputDirect : public AlsaInput
{
    public:
        AlsaInputDirect(const string& alsa_dev,
                unsigned int channels,
                unsigned int rate) :
            AlsaInput(alsa_dev, channels, rate) { }

        virtual void start() { };

        /* Read length Bytes from from the alsa device.
         * length must be a multiple of channels * bytes_per_sample.
         *
         * Returns the number of bytes read.
         */
        size_t read(uint8_t* buf, size_t length);

    private:
        AlsaInputDirect(const AlsaInputDirect& other) :
            AlsaInput("", 0, 0) { }
};

class AlsaInputThreaded : public AlsaInput
{
    public:
        AlsaInputThreaded(const string& alsa_dev,
                unsigned int channels,
                unsigned int rate,
                SampleQueue<uint8_t>& queue) :
            AlsaInput(alsa_dev, channels, rate),
            m_running(false),
            m_queue(queue) { }

        ~AlsaInputThreaded()
        {
            if (m_running) {
                m_running = false;
                m_thread.interrupt();
                m_thread.join();
            }
        }

        virtual void start();

    private:
        AlsaInputThreaded(const AlsaInputThreaded& other) :
            AlsaInput("", 0, 0),
            m_queue(other.m_queue) {}

        void process();

        bool m_running;
        boost::thread m_thread;

        SampleQueue<uint8_t>& m_queue;

};

#endif