    //=============================================================================
    //  MuseScore
    //  Music Composition & Notation
    //
    //  Copyright (C) 2012 Werner Schweer
    //
    //  This program is free software; you can redistribute it and/or modify
    //  it under the terms of the GNU General Public License version 2
    //  as published by the Free Software Foundation and appearing in
    //  the file LICENCE.GPL
    //=============================================================================

    #include "libmscore/score.h"
    #include "seq.h"
    #include <pulse/pulseaudio.h>
    #include "driver.h"
    #include "preferences.h"

    namespace Ms {

    #define FRAMES 2048

    //---------------------------------------------------------
    //   PulseAudio
    //---------------------------------------------------------

    class PulseAudio : public Driver {
          Transport state;
          int runState;
          int _sampleRate;
          pa_sample_spec ss;
          pa_mainloop* pa_ml;
          pa_buffer_attr bufattr;
          float buffer[FRAMES * 2];
          pthread_t thread;

          static void paCallback(pa_stream* s, size_t len, void* data);
          static void* paLoop(void*);

       public:
          PulseAudio(Seq*);
          virtual ~PulseAudio();
          virtual bool init(bool hot = false);
          virtual bool start(bool hotPlug = false);
          virtual bool stop();
          virtual Transport getState() override { return state; }
          virtual int sampleRate() const { return _sampleRate;          }
          virtual void stopTransport()   { state = Transport::STOP; }
          virtual void startTransport()  { state = Transport::PLAY; }
          };

    //---------------------------------------------------------
    //   paCallback
    //---------------------------------------------------------

    void PulseAudio::paCallback(pa_stream* s, size_t len, void* data)
          {
          PulseAudio* pa = (PulseAudio*)data;
          constexpr size_t n = FRAMES * 2 * sizeof(float);
          if (len > n) {
                qDebug("PulseAudio:: buffer too large!");
                len = n;
                }
          pa->seq->process(len / (2 * sizeof(float)), pa->buffer);
          pa_stream_write(s, pa->buffer, len, nullptr, int64_t(0), PA_SEEK_RELATIVE);
          }

    //---------------------------------------------------------
    //   PulseAudio
    //---------------------------------------------------------

    PulseAudio::PulseAudio(Seq* s)
       : Driver(s)
          {
          _sampleRate = preferences.alsaSampleRate;
          state       = Transport::STOP;
          runState    = 0;
          }

    //---------------------------------------------------------
    //   ~PulseAudio
    //---------------------------------------------------------

    PulseAudio::~PulseAudio()
          {
          stop();
          }

    //---------------------------------------------------------
    //   pa_state_cb
    //---------------------------------------------------------

    static void pa_state_cb(pa_context* c, void* data)
          {
          int* pa_ready = (int*)data;
          switch (pa_context_get_state(c)) {
                // These are just here for reference
                case PA_CONTEXT_UNCONNECTED:
                case PA_CONTEXT_CONNECTING:
                case PA_CONTEXT_AUTHORIZING:
                case PA_CONTEXT_SETTING_NAME:
                default:
                      break;
                case PA_CONTEXT_FAILED:
                case PA_CONTEXT_TERMINATED:
                      *pa_ready = 2;
                      break;
                case PA_CONTEXT_READY:
                      *pa_ready = 1;
                      break;
                }
          }

    //---------------------------------------------------------
    //   init
    //    return false on error
    //---------------------------------------------------------

    bool PulseAudio::init(bool)
          {
          pa_ml                     = pa_mainloop_new();
          pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml);
          pa_context* pa_ctx        = pa_context_new(pa_mlapi, "MuseScore");
          if (pa_context_connect(pa_ctx, NULL, pa_context_flags_t(0), NULL) != 0) {
                qDebug("PulseAudio Context Connect Failed with Error: %s", pa_strerror(pa_context_errno(pa_ctx)));
                return false;
                }

          int pa_ready = 0;
          pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);

          while (pa_ready == 0)
                pa_mainloop_iterate(pa_ml, 1, NULL);
          if (pa_ready == 2)
                return false;

          ss.rate     = _sampleRate;
          ss.channels = 2;
          ss.format   = PA_SAMPLE_FLOAT32LE;

          pa_stream* playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL);
          if (!playstream) {
                qDebug("pa_stream_new failed: %s", pa_strerror(pa_context_errno(pa_ctx)));
                return false;
                }
          pa_stream_set_write_callback(playstream, paCallback, this);

          bufattr.fragsize  = (uint32_t)-1;
          bufattr.maxlength = FRAMES * 2 * sizeof(float);
          bufattr.minreq    = FRAMES * 1 * sizeof(float); // pa_usec_to_bytes(0, &ss);
          bufattr.prebuf    = (uint32_t)-1;
          bufattr.tlength   = bufattr.maxlength;

          int r = pa_stream_connect_playback(playstream, nullptr, &bufattr,
             PA_STREAM_NOFLAGS, nullptr, nullptr);

          if (r < 0) {
                qDebug("pa_stream_connect_playback failed");
                pa_context_disconnect(pa_ctx);
                pa_context_unref(pa_ctx);
                pa_mainloop_free(pa_ml);
                pa_ml = 0;
                return false;
                }
          return true;
          }

    //---------------------------------------------------------
    //   paLoop
    //---------------------------------------------------------

    void* PulseAudio::paLoop(void* data)
          {
          PulseAudio* pa = (PulseAudio*)data;
          pa->runState = 2;
          while (pa->runState == 2)
                pa_mainloop_iterate(pa->pa_ml, 1, NULL);
          pa->runState = 0;
          return 0;
          }

    //---------------------------------------------------------
    //   start
    //---------------------------------------------------------

    bool PulseAudio::start(bool)
          {
          pthread_attr_t* attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t));
          pthread_attr_init(attributes);
          if (pthread_create(&thread, attributes, paLoop, this))
                perror("creating thread failed:");
          pthread_attr_destroy(attributes);
          return true;
          }

    //---------------------------------------------------------
    //   stop
    //---------------------------------------------------------

    bool PulseAudio::stop()
          {
          if (runState == 2) {
                runState = 1;
                int i = 0;
                for (;i < 4; ++i) {
                      if (runState == 0)
                            break;
                      sleep(1);
                      }
                pthread_cancel(thread);
                pthread_join(thread, 0);
                }
          return true;
          }

    //---------------------------------------------------------
    //   getPulseaudioDriver
    //    driver factory
    //---------------------------------------------------------

    Driver* getPulseAudioDriver(Seq* seq)
          {
          return new PulseAudio(seq);
          }
    }

↑ V575 The potential null pointer is passed into 'pthread_attr_init' function. Inspect the first argument.

↑ V547 Expression 'runState == 0' is always false.

↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: ss, pa_ml, bufattr, buffer, thread.