Skip to content

Commit

Permalink
rearrange linuxaudiodriver with alsa/jack
Browse files Browse the repository at this point in the history
- move out alsaaudiodriver things into alsaaudiodriver
- linuxaudiodriver is the driver hander, that musescore
  talks to, and is responsible for running jack or alsa
  • Loading branch information
lyrra committed Sep 6, 2023
1 parent c69f985 commit 80a93a2
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 130 deletions.
12 changes: 12 additions & 0 deletions src/framework/audio/iaudiodriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ class IAudioDriver : MODULE_EXPORT_INTERFACE
virtual void suspend() = 0;
};
using IAudioDriverPtr = std::shared_ptr<IAudioDriver>;

class AudioDriverState
{
public:
virtual std::string name() const = 0;
virtual bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) = 0;
virtual void close() = 0;
virtual bool isOpened() const = 0;

IAudioDriver::Spec m_spec; // current running spec
std::string m_deviceId;
};
}

#endif // MU_AUDIO_IAUDIODRIVER_H
32 changes: 17 additions & 15 deletions src/framework/audio/internal/platform/alsa/alsaaudiodriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,24 @@ using namespace mu::audio;
static void* alsaThread(void* aParam)
{
mu::runtime::setThreadName("audio_driver");
AlsaDriverState* data = static_cast<AlsaDriverState*>(aParam);
AlsaDriverState* state = static_cast<AlsaDriverState*>(aParam);

int ret = snd_pcm_wait(static_cast<snd_pcm_t*>(data->m_alsaDeviceHandle), 1000);
int ret = snd_pcm_wait(static_cast<snd_pcm_t*>(state->m_alsaDeviceHandle), 1000);
IF_ASSERT_FAILED(ret > 0) {
return nullptr;
}

while (!data->m_audioProcessingDone)
while (!state->m_audioProcessingDone)
{
uint8_t* stream = (uint8_t*)data->m_buffer;
int len = data->m_samples * data->m_channels * sizeof(float);
uint8_t* stream = (uint8_t*)state->m_buffer;
int len = state->m_spec.samples * state->m_spec.channels * sizeof(float);

data->m_callback(data->m_userdata, stream, len);
state->m_spec.callback(state->m_spec.userdata, stream, len);

snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast<snd_pcm_t*>(data->m_alsaDeviceHandle), data->m_buffer, data->m_samples);
snd_pcm_sframes_t pcm = snd_pcm_writei(static_cast<snd_pcm_t*>(state->m_alsaDeviceHandle), state->m_buffer, state->m_spec.samples);
if (pcm != -EPIPE) {
} else {
snd_pcm_prepare(static_cast<snd_pcm_t*>(data->m_alsaDeviceHandle));
snd_pcm_prepare(static_cast<snd_pcm_t*>(state->m_alsaDeviceHandle));
}
}

Expand Down Expand Up @@ -97,10 +97,10 @@ std::string AlsaDriverState::name() const

bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec)
{
m_samples = spec.samples;
m_channels = spec.channels;
m_callback = spec.callback;
m_userdata = spec.userdata;
m_spec.samples = spec.samples;
m_spec.channels = spec.channels;
m_spec.callback = spec.callback;
m_spec.userdata = spec.userdata;

int rc;
snd_pcm_t* handle;
Expand All @@ -127,7 +127,9 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a
return false;
}

snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_samples);
long unsigned int samples = m_spec.samples;
snd_pcm_hw_params_set_buffer_size_near(handle, params, &samples);
m_spec.samples = (int)samples;

rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
Expand All @@ -142,13 +144,13 @@ bool AlsaDriverState::open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* a
delete[] m_buffer;
}

m_buffer = new float[m_samples * m_channels];
m_buffer = new float[m_spec.samples * m_spec.channels];

if (activeSpec) {
*activeSpec = spec;
activeSpec->format = IAudioDriver::Format::AudioF32;
activeSpec->sampleRate = aSamplerate;
m_format = *activeSpec;
m_spec = *activeSpec;
}

m_threadHandle = 0;
Expand Down
17 changes: 5 additions & 12 deletions src/framework/audio/internal/platform/alsa/alsaaudiodriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,22 @@
#include "iaudiodriver.h"

namespace mu::audio {

class AlsaDriverState
class AlsaDriverState : public AudioDriverState
{
public:
AlsaDriverState();
~AlsaDriverState();

std::string name() const;
bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec);
void close();
bool isOpened() const;
std::string name() const override;
bool open(const IAudioDriver::Spec& spec, IAudioDriver::Spec* activeSpec) override;
void close() override;
bool isOpened() const override;

void* m_alsaDeviceHandle = nullptr;

float* m_buffer = nullptr;
unsigned long m_samples = 0;
int m_channels = 0;
bool m_audioProcessingDone = false;
pthread_t m_threadHandle = 0;
IAudioDriver::Callback m_callback;
void* m_userdata = nullptr;
IAudioDriver::Spec m_format;
std::string m_deviceId;
private:
void alsaCleanup();
};
Expand Down
112 changes: 23 additions & 89 deletions src/framework/audio/internal/platform/lin/linuxaudiodriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "linuxaudiodriver.h"
#include "../alsa/alsaaudiodriver.h" //FIX: relative path, set path in CMakeLists

#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
Expand All @@ -34,35 +35,15 @@
#include "log.h"
#include "runtime.h"

static constexpr char DEFAULT_DEVICE_ID[] = "default";

using namespace mu::audio;

void LinuxAudioDriver::alsaCleanup()
{
m_alsaDriverState->audioProcessingDone = true;
if (m_alsaDriverState->threadHandle) {
pthread_join(m_alsaDriverState->threadHandle, nullptr);
}
if (m_alsaDriverState->alsaDeviceHandle != nullptr) {
snd_pcm_t* alsaDeviceHandle = static_cast<snd_pcm_t*>(m_alsaDriverState->alsaDeviceHandle);
snd_pcm_drain(alsaDeviceHandle);
snd_pcm_close(alsaDeviceHandle);
m_alsaDriverState->alsaDeviceHandle = nullptr;
}

delete[] m_alsaDriverState->buffer;
}

LinuxAudioDriver::LinuxAudioDriver()
{
m_alsaDriverState = std::make_unique<ALSADriverState>();
m_deviceId = DEFAULT_DEVICE_ID;
m_current_audioDriverState = std::make_unique<AlsaDriverState>();
}

LinuxAudioDriver::~LinuxAudioDriver()
{
alsaCleanup();
}

void LinuxAudioDriver::init()
Expand All @@ -78,95 +59,45 @@ void LinuxAudioDriver::init()

std::string LinuxAudioDriver::name() const
{
return "MUAUDIO(ALSA)";
return m_current_audioDriverState->name();
}

bool LinuxAudioDriver::open(const Spec& spec, Spec* activeSpec)
{
m_alsaDriverState->samples = spec.samples;
m_alsaDriverState->channels = spec.channels;
m_alsaDriverState->callback = spec.callback;
m_alsaDriverState->userdata = spec.userdata;

int rc;
snd_pcm_t* handle;
rc = snd_pcm_open(&handle, outputDevice().c_str(), SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
return false;
}

m_alsaDriverState->alsaDeviceHandle = handle;

snd_pcm_hw_params_t* params;
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(handle, params);

snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT_LE);
snd_pcm_hw_params_set_channels(handle, params, spec.channels);

unsigned int aSamplerate = spec.sampleRate;
unsigned int val = aSamplerate;
int dir = 0;
rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
if (rc < 0) {
return false;
}

snd_pcm_hw_params_set_buffer_size_near(handle, params, &m_alsaDriverState->samples);

rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
return false;
}

snd_pcm_hw_params_get_rate(params, &val, &dir);
aSamplerate = val;

m_alsaDriverState->buffer = new float[m_alsaDriverState->samples * m_alsaDriverState->channels];

if (activeSpec) {
*activeSpec = spec;
activeSpec->format = Format::AudioF32;
activeSpec->sampleRate = aSamplerate;
m_alsaDriverState->format = *activeSpec;
}

m_alsaDriverState->threadHandle = 0;

LOGD() << "Connected to " << outputDevice();
return true;
return m_current_audioDriverState->open(spec, activeSpec);
}

void LinuxAudioDriver::close()
{
alsaCleanup();
return m_current_audioDriverState->close();
}

bool LinuxAudioDriver::isOpened() const
{
return m_alsaDriverState->alsaDeviceHandle != nullptr;
return m_current_audioDriverState->isOpened();
}

AudioDeviceID LinuxAudioDriver::outputDevice() const
{
return m_deviceId;
return m_current_audioDriverState->name(); // m_deviceId;
}

bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId)
{
if (m_deviceId == deviceId) {
if (m_current_audioDriverState->name() == deviceId) {
return true;
}

bool reopen = isOpened();
close();
m_deviceId = deviceId;
//FIX: no, we need to create the new device conditioned on the deviceId
bool reopen = m_current_audioDriverState->isOpened();
IAudioDriver::Spec spec(m_current_audioDriverState->m_spec);
m_current_audioDriverState->close();

bool ok = true;
if (reopen) {
ok = open(m_alsaDriverState->format, &m_alsaDriverState->format);
ok = m_current_audioDriverState->open(spec, &spec);
}
m_current_audioDriverState->m_spec = spec;

if (ok) {
m_outputDeviceChanged.notify();
Expand All @@ -177,7 +108,7 @@ bool LinuxAudioDriver::selectOutputDevice(const AudioDeviceID& deviceId)

bool LinuxAudioDriver::resetToDefaultOutputDevice()
{
return selectOutputDevice(DEFAULT_DEVICE_ID);
return selectOutputDevice("alsa"); // FIX:
}

mu::async::Notification LinuxAudioDriver::outputDeviceChanged() const
Expand All @@ -188,7 +119,8 @@ mu::async::Notification LinuxAudioDriver::outputDeviceChanged() const
AudioDeviceList LinuxAudioDriver::availableOutputDevices() const
{
AudioDeviceList devices;
devices.push_back({ DEFAULT_DEVICE_ID, trc("audio", "System default") });
devices.push_back({ "alsa", trc("audio", "ALSA") });
devices.push_back({ "jack", trc("audio", "JACK") });

return devices;
}
Expand All @@ -200,22 +132,24 @@ mu::async::Notification LinuxAudioDriver::availableOutputDevicesChanged() const

unsigned int LinuxAudioDriver::outputDeviceBufferSize() const
{
return m_alsaDriverState->format.samples;
return m_current_audioDriverState->m_spec.samples;
}

bool LinuxAudioDriver::setOutputDeviceBufferSize(unsigned int bufferSize)
{
if (m_alsaDriverState->format.samples == bufferSize) {
if (m_current_audioDriverState->m_spec.samples == (int)bufferSize) {
return true;
}

bool reopen = isOpened();
close();
m_alsaDriverState->format.samples = bufferSize;
m_current_audioDriverState->m_spec.samples = bufferSize;

bool ok = true;
if (reopen) {
ok = open(m_alsaDriverState->format, &m_alsaDriverState->format);
// FIX:
// FIX:
//ok = open(m_current_audioDriverState->m_spec, &m_current_audioDriverState->m_spec);
}

if (ok) {
Expand Down
16 changes: 2 additions & 14 deletions src/framework/audio/internal/platform/lin/linuxaudiodriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,6 @@
#include "audiodeviceslistener.h"

namespace mu::audio {
struct ALSADriverState
{
float* buffer = nullptr;
void* alsaDeviceHandle = nullptr;
unsigned long samples = 0;
int channels = 0;
bool audioProcessingDone = false;
pthread_t threadHandle = 0;
IAudioDriver::Callback callback;
void* userdata = nullptr;
IAudioDriver::Spec format;
};

class LinuxAudioDriver : public IAudioDriver, public async::Asyncable
{
public:
Expand Down Expand Up @@ -86,7 +73,8 @@ class LinuxAudioDriver : public IAudioDriver, public async::Asyncable
async::Notification m_bufferSizeChanged;
async::Notification m_sampleRateChanged;

std::unique_ptr<ALSADriverState> m_alsaDriverState;
struct IAudioDriver::Spec m_spec;
std::unique_ptr<AudioDriverState> m_current_audioDriverState;
};
}

Expand Down

0 comments on commit 80a93a2

Please sign in to comment.