Thread: SoundManagerAlsa.cpp and multi-threaded applications

  1. #1
    Registered User
    Join Date
    Nov 2014
    Posts
    26

    SoundManagerAlsa.cpp and multi-threaded applications

    I am trying to understand a few things about this SoundManagerAlsa script and multi-threading.

    Here is how the SoundManagerAlsa script is being called:

    Code:
    {
      SoundManager::SoundManager soundManager(portNumber);
      soundManager.openSoundDevice();
      soundManager.startServer();
    
      cmdQueue.get(); // blocks until a command is available in the queue
    
      soundManager.shutDown();
      }
    So from the top here's openSoundDevice():

    Code:
    void SoundManager::openSoundDevice()
      {
        initiateSoundDevice(); // Close then reopen the device.
      }
    now initiateSoundDevice():

    Code:
    void SoundManager::initiateSoundDevice()
      {
        using namespace TimeStuff;
    
        if (!m_toneDev || m_audioSetup.threadIsRunning) // If the thread is already running then shut it down and reopen the audio device.
        {
          printf("%10.3f Shut down thread.\n", fToHMS(now()));
          shutDown();
    
          assert(!m_audioSetup.threadIsRunning);
          if (m_audioSetup.threadIsRunning)
          {
            perror("Unable to shut down audio update thread");
          }
          else
          {
            printf("%10.3f Open sound device.\n", fToHMS(now()));
    
            for (int i=0 ; audioDeviceName[i] && !m_toneDev ; i++)
            {
              int result = snd_pcm_open(&m_toneDev, audioDeviceName[i], SND_PCM_STREAM_PLAYBACK, 0);
              if (result < 0)
              {
                std::cerr << "Unable to open sound device(" << audioDeviceName[i] << "), tone canceled. Errmsg: " << snd_strerror(result) << std::endl;
                m_toneDev = NULL;
              }
              else
              {
                printf("%10.3f Sound device (%s) open. Handle: %p\n", fToHMS(now()), audioDeviceName[i], m_toneDev);
              }
            }
          }
        }
    
        if (m_toneDev && !m_audioSetup.threadIsRunning) // Audio device is currently open.
        {
          m_audioSetup.clear();
          /**
           * We only want 2 periods in the ring buffer.
           * This is enough to allow uninterrupted playback, and it allows us to interrupt ongoing tones reasonably fast.
           *
           * We can have two periods in the buffer, and a third waiting to get access to the buffer.
           * This means that if we want to interrupt an ongoing tone, the reaction time will be between two and three periods.
           *
           * With
           *   sampleRate = 44100 samples per second
           *      2 periods
           *   1024 samples pr period
           * we get:
           * timePerPeriod = nSamplesPerPeriod / sampleRate = 1024 / 44100 = 23.2ms
           *
           * This means that this thread will run once per 23,2ms when a tone is being played.
           * And if the tone must be interrupted the response time is in the range [2*23.2 - 3*23.2] = [46.4 - 69.6]ms.
           */
          snd_pcm_hw_params_t *hwparams;
          snd_pcm_sw_params_t *swparams;
          snd_pcm_hw_params_alloca(&hwparams); // Allocation (alloca) is deleted when function exits.
          snd_pcm_sw_params_alloca(&swparams);
    
          // Get all parameters:
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_any(                 m_toneDev, hwparams                                ), "Unable to read hardware parameters for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_rate_resample(   m_toneDev, hwparams, 1                             ), "Unable to set re-sampling for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_access(          m_toneDev, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED ), "Unable to set interleaved format for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_format(          m_toneDev, hwparams, SND_PCM_FORMAT_S16_LE         ), "Unable to set sample format for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_channels(        m_toneDev, hwparams, m_audioSetup.nChannels        ), "Unable to set number of channels for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_rate_near(       m_toneDev, hwparams, &m_audioSetup.sampleRate, NULL), "Unable to set sample rate for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_buffer_size_near(m_toneDev, hwparams, &m_audioSetup.bufferSize      ), "Unable to set buffer size for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params_set_period_size_near(m_toneDev, hwparams, &m_audioSetup.periodSize, NULL), "Unable to set period size for sound device.");
          if (m_toneDev) handleSetupError(snd_pcm_hw_params(                     m_toneDev, hwparams                                ), "Unable to write hw parameters to sound device.");
    
          if (m_toneDev)
          {
            m_audioSetup.msPerSample = 1000.0 / static_cast<double>(m_audioSetup.sampleRate);
            printf("%10.3f Sound device Hardware setup:\n", fToHMS(now()));
            printf("          Millisec per sample: %fms\n", m_audioSetup.msPerSample);
            printf("          Millisec per period: %fms\n", m_audioSetup.msPerSample * static_cast<double>(m_audioSetup.periodSize));
            printf("             Samples per period: %u\n", static_cast<unsigned>(m_audioSetup.periodSize));
            printf("             Samples per buffer: %u\n", static_cast<unsigned>(m_audioSetup.bufferSize));
    
            m_audioSetup.audioBuffer = new int16_t[m_audioSetup.periodSize * m_audioSetup.nChannels];
            assert(m_audioSetup.audioBuffer);
    
            if (!m_audioSetup.audioBuffer)
            {
              std::cerr << "Unable to allocate audio buffer. Tone cancelled." << std::endl;
              snd_pcm_close(m_toneDev);
              m_toneDev = NULL;
            }
          }
    
          if (m_toneDev)
          {
            m_audioSetup.threadIsRunning = true;
            m_toneThread = threadfunc::ThreadCreate( 6, threadUpdateTone, this );
          }
        }
      }
    The portion that confuses me is:

    Code:
    if (!m_toneDev || m_audioSetup.threadIsRunning) // If the thread is already running then shut it down and reopen the audio device.
        {
          printf("%10.3f Shut down thread.\n", fToHMS(now()));
          shutDown();
    
          assert(!m_audioSetup.threadIsRunning);
          if (m_audioSetup.threadIsRunning)
          {
            perror("Unable to shut down audio update thread");
          }
          else
          {
            printf("%10.3f Open sound device.\n", fToHMS(now()));
    
            for (int i=0 ; audioDeviceName[i] && !m_toneDev ; i++)
            {
              int result = snd_pcm_open(&m_toneDev, audioDeviceName[i], SND_PCM_STREAM_PLAYBACK, 0);
              if (result < 0)
              {
                std::cerr << "Unable to open sound device(" << audioDeviceName[i] << "), tone canceled. Errmsg: " << snd_strerror(result) << std::endl;
                m_toneDev = NULL;
              }
              else
              {
                printf("%10.3f Sound device (%s) open. Handle: %p\n", fToHMS(now()), audioDeviceName[i], m_toneDev);
              }
            }
          }
        }
    What is going on here? Why would you have a multi-threaded audio device? You only have one speaker, you can't play two tones at once, so whats the point? I mean it even stops the currently running thread from running whenever initiateSoundDevice() is called doesn't it? Why would this be a threaded application?
    Last edited by Robert Murch; 02-07-2019 at 01:44 PM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    26,530
    I think the hint lies in the comment: "This means that this thread will run once per 23,2ms when a tone is being played." So, it looks like the thread exists so that it can be perdiocally put to sleep then run.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Nov 2014
    Posts
    26
    Quote Originally Posted by laserlight View Post
    I think the hint lies in the comment: "This means that this thread will run once per 23,2ms when a tone is being played." So, it looks like the thread exists so that it can be perdiocally put to sleep then run.
    I always miss the most obvious things... thank you. Okay so the thread is there just for debugging purposes you are thinking?

    I am thinking I can stop the multithreading just by saying something like:

    Code:
    void SoundManager::reopenSoundDevice()
      {
        if (m_audioSetup.threadIsRunning){}
        else{
           initiateSoundDevice();
        }
      }
    Does that sound right? I am new to threading... maybe I should just say: m_toneMutex.wait()
    Last edited by Robert Murch; 02-07-2019 at 05:05 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multi-threaded mayhem
    By IceDane in forum C Programming
    Replies: 8
    Last Post: 03-24-2008, 08:44 AM
  2. Going from single-threaded to multi-threaded
    By Dino in forum C Programming
    Replies: 11
    Last Post: 03-23-2008, 01:14 PM
  3. gdb problem in multi-threaded app
    By IfYouSaySo in forum Linux Programming
    Replies: 1
    Last Post: 10-12-2006, 08:22 PM
  4. multi-threaded programming
    By Hermitsky in forum C++ Programming
    Replies: 29
    Last Post: 11-28-2004, 01:23 PM
  5. Multi-Threaded Sockets
    By XSquared in forum Networking/Device Communication
    Replies: 9
    Last Post: 08-28-2003, 09:54 PM

Tags for this Thread