~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Source/Core/AudioCommon/Src/AlsaSoundStream.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 Dolphin Emulator Project
 
2
// Licensed under GPLv2
 
3
// Refer to the license.txt file included.
 
4
 
 
5
#include <functional>
 
6
 
 
7
#include "Common.h"
 
8
#include "Thread.h"
 
9
#include "AlsaSoundStream.h"
 
10
 
 
11
#define FRAME_COUNT_MIN 256
 
12
#define BUFFER_SIZE_MAX 8192
 
13
#define BUFFER_SIZE_BYTES (BUFFER_SIZE_MAX*2*2)
 
14
 
 
15
AlsaSound::AlsaSound(CMixer *mixer) : SoundStream(mixer), thread_data(0), handle(NULL), frames_to_deliver(FRAME_COUNT_MIN)
 
16
{
 
17
        mix_buffer = new u8[BUFFER_SIZE_BYTES];
 
18
}
 
19
 
 
20
AlsaSound::~AlsaSound()
 
21
{
 
22
        delete [] mix_buffer;
 
23
}
 
24
 
 
25
bool AlsaSound::Start()
 
26
{
 
27
        thread = std::thread(std::mem_fun(&AlsaSound::SoundLoop), this);
 
28
        thread_data = 0;
 
29
        return true;
 
30
}
 
31
 
 
32
void AlsaSound::Stop()
 
33
{
 
34
        thread_data = 1;
 
35
        thread.join();
 
36
}
 
37
 
 
38
void AlsaSound::Update()
 
39
{
 
40
        // don't need to do anything here.
 
41
}
 
42
 
 
43
// Called on audio thread.
 
44
void AlsaSound::SoundLoop()
 
45
{
 
46
        if (!AlsaInit()) {
 
47
                thread_data = 2;
 
48
                return;
 
49
        }
 
50
        Common::SetCurrentThreadName("Audio thread - alsa");
 
51
        while (!thread_data)
 
52
        {
 
53
                m_mixer->Mix(reinterpret_cast<short *>(mix_buffer), frames_to_deliver);
 
54
                int rc = m_muted ? 1337 : snd_pcm_writei(handle, mix_buffer, frames_to_deliver);
 
55
                if (rc == -EPIPE)
 
56
                {
 
57
                        // Underrun
 
58
                        snd_pcm_prepare(handle);
 
59
                }
 
60
                else if (rc < 0) 
 
61
                {
 
62
                        ERROR_LOG(AUDIO, "writei fail: %s", snd_strerror(rc));
 
63
                }
 
64
        }
 
65
        AlsaShutdown();
 
66
        thread_data = 2;
 
67
}
 
68
 
 
69
bool AlsaSound::AlsaInit()
 
70
{
 
71
        unsigned int sample_rate = m_mixer->GetSampleRate();
 
72
        int err;
 
73
        int dir;
 
74
        snd_pcm_sw_params_t *swparams;
 
75
        snd_pcm_hw_params_t *hwparams;
 
76
        snd_pcm_uframes_t buffer_size,buffer_size_max;
 
77
        unsigned int periods;
 
78
 
 
79
        err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
 
80
        if (err < 0) 
 
81
        {
 
82
                ERROR_LOG(AUDIO, "Audio open error: %s\n", snd_strerror(err));
 
83
                return false;
 
84
        }
 
85
 
 
86
        snd_pcm_hw_params_alloca(&hwparams);
 
87
 
 
88
        err = snd_pcm_hw_params_any(handle, hwparams);
 
89
        if (err < 0) 
 
90
        {
 
91
                ERROR_LOG(AUDIO, "Broken configuration for this PCM: %s\n", snd_strerror(err));
 
92
                return false;
 
93
        }
 
94
        
 
95
        err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
 
96
        if (err < 0) 
 
97
        {
 
98
                ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err));
 
99
                return false;
 
100
        }
 
101
 
 
102
        err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE);
 
103
        if (err < 0) 
 
104
        {
 
105
                ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err));
 
106
                return false;
 
107
        }
 
108
 
 
109
        dir = 0;
 
110
        err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &sample_rate, &dir);
 
111
        if (err < 0) 
 
112
        {
 
113
                ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err));
 
114
                return false;
 
115
        }
 
116
 
 
117
        err = snd_pcm_hw_params_set_channels(handle, hwparams, 2);
 
118
        if (err < 0) 
 
119
        {
 
120
                ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err));
 
121
                return false;
 
122
        }
 
123
 
 
124
        periods = BUFFER_SIZE_MAX / FRAME_COUNT_MIN;
 
125
        err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, &dir);
 
126
        if (err < 0) 
 
127
        {
 
128
                ERROR_LOG(AUDIO, "Cannot set Minimum periods: %s\n", snd_strerror(err));
 
129
                return false;
 
130
        }
 
131
 
 
132
        buffer_size_max = BUFFER_SIZE_MAX;
 
133
        err = snd_pcm_hw_params_set_buffer_size_max(handle, hwparams, &buffer_size_max);
 
134
        if (err < 0) 
 
135
        {
 
136
                ERROR_LOG(AUDIO, "Cannot set minimum buffer size: %s\n", snd_strerror(err));
 
137
                return false;
 
138
        }
 
139
 
 
140
        err = snd_pcm_hw_params(handle, hwparams);
 
141
        if (err < 0) 
 
142
        {
 
143
                ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err));
 
144
                return false;
 
145
        }
 
146
 
 
147
        err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
 
148
        if (err < 0) 
 
149
        {
 
150
                ERROR_LOG(AUDIO, "Cannot get buffer size: %s\n", snd_strerror(err));
 
151
                return false;
 
152
        }
 
153
 
 
154
        err = snd_pcm_hw_params_get_periods_max(hwparams, &periods, &dir);
 
155
        if (err < 0) 
 
156
        {
 
157
                ERROR_LOG(AUDIO, "Cannot get periods: %s\n", snd_strerror(err));
 
158
                return false;
 
159
        }
 
160
 
 
161
        //periods is the number of fragments alsa can wait for during one 
 
162
        //buffer_size
 
163
        frames_to_deliver = buffer_size / periods;
 
164
        //limit the minimum size. pulseaudio advertises a minimum of 32 samples.
 
165
        if (frames_to_deliver < FRAME_COUNT_MIN)
 
166
                frames_to_deliver = FRAME_COUNT_MIN;
 
167
        //it is probably a bad idea to try to send more than one buffer of data
 
168
        if ((unsigned int)frames_to_deliver > buffer_size)
 
169
                frames_to_deliver = buffer_size;
 
170
        NOTICE_LOG(AUDIO, "ALSA gave us a %ld sample \"hardware\" buffer with %d periods. Will send %d samples per fragments.\n", buffer_size, periods, frames_to_deliver);
 
171
 
 
172
        snd_pcm_sw_params_alloca(&swparams);
 
173
 
 
174
        err = snd_pcm_sw_params_current(handle, swparams);
 
175
        if (err < 0) 
 
176
        {
 
177
                ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err));
 
178
                return false;
 
179
        }
 
180
 
 
181
        err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U);
 
182
        if (err < 0) 
 
183
        {
 
184
                ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err));
 
185
                return false;
 
186
        }
 
187
 
 
188
        err = snd_pcm_sw_params(handle, swparams);
 
189
        if (err < 0) 
 
190
        {
 
191
                ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err));
 
192
                return false;
 
193
        }
 
194
 
 
195
        err = snd_pcm_prepare(handle);
 
196
        if (err < 0) 
 
197
        {
 
198
                ERROR_LOG(AUDIO, "Unable to prepare: %s\n", snd_strerror(err));
 
199
                return false;
 
200
        }
 
201
        NOTICE_LOG(AUDIO, "ALSA successfully initialized.\n");
 
202
        return true;
 
203
}
 
204
 
 
205
void AlsaSound::AlsaShutdown()
 
206
{
 
207
        if (handle != NULL)
 
208
        {
 
209
                snd_pcm_drop(handle);
 
210
                snd_pcm_close(handle);
 
211
                handle = NULL;
 
212
        }
 
213
}
 
214