Exemplo n.º 1
0
static int processRequest(char *request) {
    int count = 0;
    int responseTotal = 0;
    
    config_setting_t *responseConfig = NULL;
    config_setting_t *responseCurrent = NULL;
    const char *responseValue = NULL;
    const char *requestName = NULL;
    const char *requestValue = NULL;
    long volume;
    
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    pthread_mutex_lock(&lockConfig);
    
    responseConfig = config_lookup(&config, "response");
    responseTotal = config_setting_length(responseConfig);
    
    for(count = 0; count < responseTotal; count++) {
        responseCurrent = config_setting_get_elem(responseConfig, count);
        if((responseValue = config_setting_get_string_elem(responseCurrent, 1)) != NULL &&
        strcmp(responseValue, request) == 0) {
            responseValue = config_setting_get_string_elem(responseCurrent, 2);
            if(config_setting_get_bool_elem(responseCurrent, 0) == 1) { // formulating default response
            
                pthread_mutex_unlock(&lockConfig);
                pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
                
                common_data.interface->reply(responseValue, strlen(responseValue));
            }
            else { // attempt to formulate custom response
                requestName = config_setting_name(responseCurrent);
                
                pthread_mutex_unlock(&lockConfig);
                pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
                
                if(strcmp(requestName, "volume") == 0) {
                    if(getMixer(&volume) == EXIT_FAILURE) {
                        return EXIT_FAILURE;
                    }
                    replyVolumeCommand(&volume);
                }
                else {
                    statusInfo.retrieve(requestName, &requestValue);
                    if(requestValue != NULL)
                        replyDeviceCommand((char *)requestName, (char *)requestValue);
                    else // custom response not possible, reverting to default value
                        replyDeviceCommand((char *)requestName, (char *)responseValue);
                }
            }
            syslog(LOG_DEBUG, "Successfully processed request: %s", request);
            return EXIT_SUCCESS; // command is matched, returning
        }
        else {
            pthread_mutex_unlock(&lockConfig);
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        }
    }
    syslog(LOG_DEBUG, "Could not identify request: %s", request);
    return EXIT_SUCCESS;
}
Exemplo n.º 2
0
int AmeSystemSound::setupMixer(QString card, QString device)
{
    char *name;
    long int a, b;
    long alsa_min_vol = 0, alsa_max_vol = 100;
    int err, index;
    mixer_element = 0;

    qDebug("AmeSystemSound::SoundOutput: setupMixer()");

    if ((err = getMixer(&mixer, card)) < 0)
        return err;

    parseMixerName(device.toAscii().data(), &name, &index);

    mixer_element = getMixerElem(mixer, name, index);

    free(name);

    if (!mixer_element)
    {
        qWarning("SoundOutput: Failed to find mixer element");
        return -1;
    }

    /* This hack was copied from xmms.
     * Work around a bug in alsa-lib up to 1.0.0rc2 where the
     * new range don't take effect until the volume is changed.
     * This hack should be removed once we depend on Alsa 1.0.0.
     */
    snd_mixer_selem_get_playback_volume(mixer_element, SND_MIXER_SCHN_FRONT_LEFT, &a);
    snd_mixer_selem_get_playback_volume(mixer_element, SND_MIXER_SCHN_FRONT_RIGHT, &b);

    snd_mixer_selem_get_playback_volume_range(mixer_element,
            &alsa_min_vol, &alsa_max_vol);
    snd_mixer_selem_set_playback_volume_range(mixer_element, 0, 100);

    if (alsa_max_vol == 0)
    {
	mixer_element = NULL;
        return -1;
    }

    setVolume(a * 100 / alsa_max_vol);

    qDebug("SoundOutput: setupMixer() success");

    return 0;
}
Exemplo n.º 3
0
int VolumeALSA::setupMixer(QString card, QString device)
{
    char *name;
    int err, index;
    pcm_element = 0;

    qDebug("OutputALSA: setupMixer()");

    if ((err = getMixer(&m_mixer, card)) < 0)
        return err;

    parseMixerName(device.toAscii().data(), &name, &index);

    pcm_element = getMixerElem(m_mixer, name, index);

    free(name);

    if (!pcm_element)
    {
        qWarning("OutputALSA: Failed to find mixer element");
        return -1;
    }

    if((err = snd_mixer_selem_set_playback_volume_range(pcm_element, 0, 100)) < 0)
    {
        qWarning("OutputALSA: Unable to set volume range: %s", snd_strerror(-err));
        pcm_element = NULL;
        return -1;
    }

    // setup socket notifiers to monitor the state changes of the mixer
    int n = snd_mixer_poll_descriptors_count(m_mixer);
    if(n > 0)
    {
        struct pollfd* fds = new struct pollfd[n];
        n = snd_mixer_poll_descriptors(m_mixer, fds, n);
        for(int i = 0; i < n; ++i)
        {
            int sock = fds[i].fd;
            QSocketNotifier* sn = new QSocketNotifier(sock, QSocketNotifier::Read, this);
            connect(sn, SIGNAL(activated(int)), SIGNAL(changed()));
        }
        delete []fds;
    }

    qDebug("OutputALSA: setupMixer() success");
    return 0;
}
Exemplo n.º 4
0
int main(int argc, char *argv[])
{
  /*****
   * boolean value indicates when to break main loop
   * (and thus finish this configuration tool)
   *****/
  int request_finish = 0;

  int current         = 0; /***** menu related variables */
  int menu_items      = 7;
  enum state status[] = {invalid, invalid, inactive, inactive, inactive, inactive, invalid};

  WINDOW *mainscr; /***** ncurses related variables */
  int i, j;

  /* ***** detect available mixer devices */

  mixer_devices = scanMixerDevices();
  if (mixer_devices == NULL || mixer_devices->count == 0)
  {
    /* ***** no mixer devices available -> exit! */

    fprintf(stderr, "No mixer devices available!\n");
    fprintf(stderr, "Please purchase a sound card and install it!\n");
    exit(-1);
  }
  else
  {
    if (mixer_devices->count == 1) /***** exactly one mixer device available */
    {
      setMixer(mixer_devices->name[0]); /***** set this mixer */

      if (initMixer() == MIXER_OK) /***** if mixer is ok, keep it */
      {
	status[0] = ok;
	status[2] = invalid;
      }
      else                         /***** otherwise, exit!*/
      {
	fprintf(stderr, "Couldn't init the only available mixer device: /dev/%s\n",
		mixer_devices->name[0]);
	exit(-1);
      }
    }
    else /* ***** more than one device available! */
    {
      /* ***** use /dev/mixer as default if it exists */

      for (i = 0; i < mixer_devices->count; i++)
      {
	if (strcmp(mixer_devices->name[i], "mixer") == 0)
	{
	  setMixer("mixer");
	  if (initMixer() == MIXER_OK)
	  {
	    status[0] = ok;
	    status[2] = invalid;
	  }
	  else
	    noMixer();
	
	  break;
	}
      }
    }
  }

  /* ***** detect available audio devices */

  audio_devices = scanAudioDevices();
  if (audio_devices == NULL || audio_devices->count == 0)
  {
    /* ***** no audio devices available! */

    fprintf(stderr, "No audio device available that\n");
    fprintf(stderr, "supports 16bit recording!\n");
    fprintf(stderr, "Please purchase a sound card and install it!\n");
    exit(-1);
  }
  else
  {
    if (audio_devices->count == 1) /***** exactly one audio device available */
    {
      setAudio(audio_devices->name[0]); /***** set this audio device */

      if (initAudio() == AUDIO_OK) /***** if audio device is ok, keep it */
      {
	status[1] = ok;
      }
      else                         /***** otherwise, exit!*/
      {
	fprintf(stderr, "Couldn't init the only available audio device: /dev/%s\n",
		audio_devices->name[0]);
	exit(-1);
      }
    }
    else /* ***** more than one device available! */
    {
      /* ***** use /dev/dspW as default if it exists */

      for (i = 0; i < audio_devices->count; i++)
      {
	if (strcmp(audio_devices->name[i], "dspW") == 0)
	{
	  setAudio("dspW");
	  if (initAudio() == AUDIO_OK)
	    status[1] = ok;
	  else
	    noAudio();
	
	  break;
	}
      }
    }
  }

  /*****
   * if mixer and audio device have been selected successfully,
   * set menu cursor to next available menu item
   *****/
  if (status[0] == ok && status[1] == ok)
    current = 2;

  /***** ignore Ctrl-C */

  signal(SIGINT, SIG_IGN);

  /* ***** ncurses stuff */

  initscr();      /* initialize the curses library */

  if (color_term != -1) /***** define dialog color pairs if terminal supports colors */
   {
      start_color ();
      if ((color_term = has_colors ()))
      {
         color_term = 1;
         init_pair (1, COLOR_WHITE, COLOR_BLUE);
         init_pair (2, COLOR_YELLOW, COLOR_BLUE);
         init_pair (3, COLOR_BLUE, COLOR_YELLOW);
         init_pair (4, COLOR_YELLOW, COLOR_CYAN);
      }
   }
   else
      color_term = 0;

  keypad(stdscr, TRUE);  /* enable keyboard mapping */
  scrollok (stdscr, FALSE);
  cbreak();              /* take input chars one at a time, no wait for \n */
  noecho();              /* don't echo input */
  refresh();

  mainscr = popupWindow(COLS, LINES); /***** dialog window that contains the main menu */
  leaveok (mainscr, FALSE);

  while (!request_finish)
  {
    wattrset (mainscr, color_term ? COLOR_PAIR(2) | A_BOLD : A_NORMAL); /***** set bg color of the dialog */

    /*****
     * draw a box around the dialog window
     * and empty it.
     *****/
    box(mainscr, 0, 0);
    for (i = 1; i < COLS-1; i++)
      for (j = 1; j < LINES-1; j++)
	mvwaddch(mainscr, j, i, ' ');

    /***** dialog header */

    mvwaddstr(mainscr, 1, 2, "CVoiceControl");
    mvwaddstr(mainscr, 1, COLS - strlen("(c) 2000 Daniel Kiecza") - 2, "(c) 2000 Daniel Kiecza");
    mvwaddseparator(mainscr, 2, COLS);

    mvwaddstr(mainscr, 3, (COLS / 2) - (strlen ("Recording Device Configuration Tool") / 2),
	      "Recording Device Configuration Tool");
    mvwaddseparator(mainscr, 4, COLS);

    /***** main menu */

    mvwaddstr(mainscr, 5, 2, "Please Select:");

    setHighlight(mainscr, status[0], current == 0);
    mvwaddstr(mainscr, 7,5,"Select Mixer Device");
    if (mixerOK() == MIXER_OK)
    {
      mvwaddstr(mainscr, 7,24," ("); waddstr(mainscr, getMixer()); waddstr(mainscr, ")");
    }
    else
      mvwaddstr(mainscr, 7,24," (none selected!)");

    setHighlight(mainscr, status[1], current == 1);
    mvwaddstr(mainscr, 8,5,"Select Audio Device");
    if (audioOK() == AUDIO_OK)
    {
      mvwaddstr(mainscr, 8,24," ("); waddstr(mainscr, getAudio()); waddstr(mainscr, ")");
    }
    else
      mvwaddstr(mainscr, 8,24," (none selected!)");

    setHighlight(mainscr, status[2], current == 2);
    mvwaddstr(mainscr,  9,5,"Adjust Mixer Levels");
    setHighlight(mainscr, status[3], current == 3);
    mvwaddstr(mainscr, 10,5,"Calculate Recording Thresholds");
    setHighlight(mainscr, status[4], current == 4);
    mvwaddstr(mainscr, 11,5,"Estimate Characteristics of Recording Channel");
    setHighlight(mainscr, status[5], current == 5);
    mvwaddstr(mainscr, 12,5,"Write Configuration");
    setHighlight(mainscr, status[6], current == 6);
    mvwaddstr(mainscr, 13,5,"Exit");

    wmove(mainscr, 5, 17);  /***** set cursor to an appropriate location */
    wrefresh(mainscr);     /***** refresh the dialog */

    /* process the command keystroke */

    switch(getch())
    {
    case KEY_UP:   /***** cursor up */
      current = (current == 0 ? menu_items - 1 : current - 1);
      while(status[current] == inactive)
	current = (current == 0 ? menu_items - 1 : current - 1);
      break;
    case KEY_DOWN: /***** cursor down */
      current = (current == menu_items-1 ? 0 : current + 1);
      while(status[current] == inactive)
	current = (current == menu_items-1 ? 0 : current + 1);
      break;
    case ENTER:    /***** handle menu selections */
    case BLANK:
      switch (current)
      {
      case 0: /***** select mixer device */
	status[0] = invalid;
	status[2] = inactive;
	status[3] = inactive;
	status[4] = inactive;
	status[5] = inactive;
	noMixer();
	if (selectMixer() == MIXER_OK)
	{
	  status[0] = ok;
	  status[2] = invalid;
	}
	break;
      case 1: /***** select audio device */
	status[1] = invalid;
	status[3] = inactive;
	status[4] = inactive;
	status[5] = inactive;
	noAudio();
	if (selectAudio() == AUDIO_OK)
	  status[1] = ok;
	break;
      case 2: /***** adjust mixer levels */
	if (adjustMixerLevels())
	{
	  status[2] = ok;
	  status[3] = invalid;
	  status[4] = invalid;
	}
	break;
      case 3: /***** calculate recording thresholds */
	if (calculateThresholds())
	  status[3] = ok;
	else
	  status[3] = invalid;
	break;
      case 4: /***** estimate the characteristics of the recording channel */
	if (estimateChannelMean())
	  status[4] = ok;
	else
	  status[4] = invalid;
	break;
      case 5: /***** save configuration! */
	if (saveConfiguration())
	{
	  status[5] = ok;
	  status[6] = ok;
	}
	break;
      case 6: /***** leave program */
	if (status[6] == ok  ||  (status[6] != ok && safeExit()))
	{
	  wrefresh(mainscr);     /***** refresh the dialog */
  	  request_finish = 1;
	  delwin(mainscr);   /***** delete ncurses dialog window */
	 }
	break;
      }
      break;
    }

    /***** if the configuration is done, activate the menu item "Save Configuration" */

    if (status[0] != ok || status[1] != ok ||
	status[2] != ok || status[3] != ok ||
	status[4] != ok)
      status[5] = inactive;
    else if (status[5] != ok)
      status[5] = invalid;
  }

  endwin();               /* we're done */

  /***** free memory used by the list of mixer and audio devices */

  if (mixer_devices != NULL)
  {
    for (i = 0; i < mixer_devices->count; i++)
      free(mixer_devices->name[i]);
    free(mixer_devices->name);
    free(mixer_devices);
  }

  if (audio_devices != NULL)
  {
    for (i = 0; i < audio_devices->count; i++)
      free(audio_devices->name[i]);
    free(audio_devices->name);
    free(audio_devices);
  }

  exit(0);
}
Exemplo n.º 5
0
int saveConfiguration()
{
  char *home;        /***** config file related variables */
  char *config_dir;
  char *config_file;
  FILE *f;

  int retval = 0;  /***** return value */

  int width = 60, height = 11, i, j;               /***** ncurses related variables */
  WINDOW *savescr = popupWindow (width, height);

  wattrset (savescr, color_term ? COLOR_PAIR(2) | A_BOLD : A_NORMAL); /***** set bg color of the dialog */

  /*****
   * draw a box around the dialog window
   * and empty it.
   *****/
  werase (savescr);
  box (savescr, 0, 0);
  for (i = 1; i < width-1; i++)
    for (j = 1; j < height-1; j++)
      mvwaddch(savescr, j, i, ' ');

  /***** dialog header */

  mvwaddstr(savescr, 1, 2, "Save Configuration:");
  mvwaddseparator(savescr, 2, width);

  /***** dialog message */

  mvwaddstr(savescr, 4, 2, "Your configuration will be saved to");
  mvwaddstrcntr(savescr, 6, width, "~/.cvoicecontrol/config");
  mvwaddstrcntr(savescr, 8, width, "Press any key to proceed ...");

  wmove(savescr, 1, 22);  /***** set cursor to an appropriate location */
  wrefresh (savescr);     /***** refresh the dialog */
  getch();                  /***** wait for keyboard reaction */

  /***** clear dialog */

  for (i = 1; i < width-1; i++)
    for (j = 3; j < height-1; j++)
      mvwaddch(savescr, j, i, ' ');

  wmove(savescr, 1, 22);  /***** set cursor to an appropriate location */
  wrefresh (savescr);     /***** refresh the dialog */

  /***** retrieve home directory */

  home = getenv("HOME");
  if (home != NULL)
  {
    FILE *f;

    /***** make sure the config_dir "~/.cvoicecontrol/" exists */

    config_dir = malloc(strlen(home) + strlen("/.cvoicecontrol/") + 1);
    strcpy(config_dir, home);
    strcat(config_dir, "/.cvoicecontrol/");

    if ((f = fopen(config_dir, "r")) == NULL)
    {
      char *command = malloc(strlen("mkdir ") + strlen(config_dir) + 1);
      strcpy(command, "mkdir ");
      strcat(command, config_dir);
      system(command);

      if ((f = fopen(config_dir, "r")) == NULL)
      {
	free(config_dir);
	config_dir = malloc(strlen("/tmp/") + 1);
	strcpy(config_dir, "/tmp/");
      }

      free(command);
    }
    fclose(f);

    free(home);
  }
  else /***** couldn't retrieve home directory -> store results in /tmp/ */
  {
    config_dir = malloc(strlen("/tmp/") + 1);
    strcpy(config_dir, "/tmp/");
  }

  /***** tell user if home directory couldn't be retrieved and /tmp/ is used instead */

  if (strcmp(config_dir, "/tmp/") == 0)
  {
    mvwaddstr(savescr, 4, 2, "Failed to retrieve your home directory,");
    mvwaddstr(savescr, 5, 2, "please contact your local system admin!");
    mvwaddstr(savescr, 6, 2, "Configuration will be stored to /tmp/ instead!");

    wmove(savescr, 1, 22);  /***** set cursor to an appropriate location */
    wrefresh (savescr);     /***** refresh the dialog */
    getch();                /***** wait for keyboard reaction */
  }

  /***** config_file = config_dir+"config" */

  config_file = malloc(strlen(config_dir) + strlen("config") + 1);
  strcpy(config_file, config_dir);
  strcat(config_file, "config");
  free (config_dir);

  if ((f = fopen(config_file, "w")) == NULL) /***** failed to write config file */
  {
    /***** clear dialog */

    for (i = 1; i < width-1; i++)
      for (j = 3; j < height-1; j++)
	mvwaddch(savescr, j, i, ' ');

    /***** dialog message */

    mvwaddstr(savescr, 5, 2, "Failed to create your configuration file! Oops!");
    mvwaddstr(savescr, 6, 2, "What's going on?");
    mvwaddstrcntr(savescr, 8, width, "Press any key to return to menu ...");

    wmove(savescr, 1, 22);  /***** set cursor to an appropriate location */
    wrefresh (savescr);     /***** refresh the dialog */
    getch();                /***** wait for keyboard reaction */

    retval = 0;  /***** set return value to ERROR */
    goto saveConfigurationReturn;
  }

  /***** output configuration information to config file */

  fprintf(f, "Mixer Device    = %s\n", getMixer());
  fprintf(f, "Audio Device    = %s\n", getAudio());
  fprintf(f, "Mic Level       = %d\n", mic_level);
  fprintf(f, "IGain Level     = %d\n", igain_level);
  fprintf(f, "Record Level    = %d\n", rec_level);
  fprintf(f, "Stop Level      = %d\n", stop_level);
  fprintf(f, "Silence Level   = %d\n", silence_level);
  fprintf(f, "Channel Mean    =");
  for (i = 0; i < FEAT_VEC_SIZE; i++)
    fprintf(f, " %6.5f", channel_mean[i]);
  fprintf(f, "\n");
  fclose(f);

  /***** clear dialog */

  for (i = 1; i < width-1; i++)
    mvwaddch(savescr, 1, i, ' ');
  for (i = 1; i < width-1; i++)
    for (j = 3; j < height-1; j++)
      mvwaddch(savescr, j, i, ' ');

  /***** update dialog to tell user that the configuration has been saved successfully */

  mvwaddstr(savescr, 1, 2, "Success!");

  mvwaddstr(savescr, 4, 2, "Your configuration has been saved successfully to");
  mvwaddstr(savescr, 5, 4, config_file);
  mvwaddstr(savescr, 7, 2, "CVoiceControl is now ready to use!");
  mvwaddstrcntr(savescr, 9, width, "Press any key to return to menu ...");

  retval = 1; /***** set return value to ok */

  wmove(savescr, 1, 11);  /***** set cursor to an appropriate location */
  wrefresh (savescr);     /***** refresh the dialog */
  getch();                /***** wait for keyboard reaction */

 saveConfigurationReturn:

  free(config_file);
  return(retval);
}
Exemplo n.º 6
0
Workflow::OutputBuffer*
TrackWorkflow::getOutput( qint64 currentFrame, qint64 subFrame, bool paused )
{
    QReadLocker     lock( m_clipsLock );

    QMap<qint64, ClipWorkflow*>::iterator       it = m_clips.begin();
    QMap<qint64, ClipWorkflow*>::iterator       end = m_clips.end();
    bool                                        needRepositioning;
    Workflow::OutputBuffer                      *ret = NULL;
    Workflow::Frame                             *frames[EffectsEngine::MaxFramesForMixer];
    quint32                                     frameId = 0;
    bool                                        renderOneFrame = false;

    if ( m_lastFrame == -1 )
        m_lastFrame = currentFrame;
    {
        QMutexLocker      lock2( m_renderOneFrameMutex );
        if ( m_renderOneFrame == true )
        {
            m_renderOneFrame = false;
            renderOneFrame = true;
        }
    }
    {
        // This is a bit hackish : when we want to pop a frame in renderOneFrame mode,
        // we also set the position to avoid the stream to be missynchronized.
        // this frame setting will most likely toggle the next condition as true
        // If this condition is true, the clipworkflow will flush all its buffer
        // as we need to resynchronize after a setTime, so this condition has to remain
        // false. Easy ain't it?
        if ( paused == true && subFrame != m_lastFrame && renderOneFrame == false)
            needRepositioning = true;
        else
            needRepositioning = ( abs( subFrame - m_lastFrame ) > 1 ) ? true : false;
    }
    memset( frames, 0, sizeof(*frames) * EffectsEngine::MaxFramesForMixer );
    while ( it != end )
    {
        qint64          start = it.key();
        ClipWorkflow*   cw = it.value();
        //Is the clip supposed to render now?
        if ( start <= currentFrame && currentFrame <= start + cw->getClipHelper()->length() )
        {
            ret = renderClip( cw, currentFrame, start, needRepositioning,
                              renderOneFrame, paused );
            if ( m_trackType == Workflow::VideoTrack )
            {
                frames[frameId] = static_cast<Workflow::Frame*>( ret );
                ++frameId;
            }
        }
        //Is it about to be rendered?
        else if ( start > currentFrame &&
                start - currentFrame < TrackWorkflow::nbFrameBeforePreload )
            preloadClip( cw );
        //Is it supposed to be stopped?
        else
            stopClipWorkflow( cw );
        ++it;
    }
    //Handle mixers:
    if ( m_trackType == Workflow::VideoTrack )
    {
        EffectHelper*   mixer = getMixer( currentFrame );
        if ( mixer != NULL && frames[0] != NULL ) //There's no point using the mixer if there's no frame rendered.
        {
            //FIXME: We don't handle mixer3 yet.
            mixer->effectInstance()->process( currentFrame * 1000.0 / m_fps,
                                    frames[0]->buffer(),
                                    frames[1] != NULL ? frames[1]->buffer() : MainWorkflow::getInstance()->blackOutput()->buffer(),
                                    NULL, m_mixerBuffer->buffer() );
            m_mixerBuffer->ptsDiff = frames[0]->ptsDiff;
            ret = m_mixerBuffer;
        }
        else //If there's no mixer, just use the first frame, ignore the rest. It will be cleaned by the responsible ClipWorkflow.
            ret = frames[0];
        //Now handle filters :
        quint32     *newFrame = applyFilters( ret != NULL ? static_cast<const Workflow::Frame*>( ret ) : MainWorkflow::getInstance()->blackOutput(),
                                                currentFrame, currentFrame * 1000.0 / m_fps );
        if ( newFrame != NULL )
        {
            if ( ret != NULL )
                static_cast<Workflow::Frame*>( ret )->setBuffer( newFrame );
            else //Use the m_mixerBuffer as the frame to return. Ugly but avoid another attribute.
            {
                m_mixerBuffer->setBuffer( newFrame );
                ret = m_mixerBuffer;
            }
        }
    }
    m_lastFrame = subFrame;
    return ret;
}