コード例 #1
0
/*----------------------------------------------------------------------
|    AlsaOutput_Prepare
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Prepare(AlsaOutput* self)
{
    int ior;

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
    /* we need to be configured already for 'prepare' to work */
    return BLT_FAILURE;

      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* prepare the device */
        ATX_LOG_FINER("snd_pcm_prepare");

        ior = snd_pcm_prepare(self->device_handle);
        if (ior != 0) {
            ATX_LOG_FINER_2("snd_pcm_prepare() failed (%d : %s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }
        break;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* ignore */
        return BLT_SUCCESS;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_PREPARED);

    return BLT_SUCCESS;
}
コード例 #2
0
/*----------------------------------------------------------------------
|    AlsaOutput_Close
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Close(AlsaOutput* self)
{
    ATX_LOG_FINER("closing output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* wait for buffers to finish */
        ATX_LOG_FINER("snd_pcm_drain");
        snd_pcm_drain(self->device_handle);
        /* FALLTHROUGH */

      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* close the device */
        ATX_LOG_FINER("snd_pcm_close");
        snd_pcm_close(self->device_handle);
        self->device_handle = NULL;
        break;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CLOSED);

    return BLT_SUCCESS;
}
コード例 #3
0
/*----------------------------------------------------------------------
|    AlsaOutput_Open
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Open(AlsaOutput* self)
{
    int io_result;

    ATX_LOG_FINE_1("openning output - name=%s", ATX_CSTR(self->device_name));

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
        ATX_LOG_FINER("snd_pcm_open");
        io_result = snd_pcm_open(&self->device_handle,
                                 ATX_CSTR(self->device_name),
                                 SND_PCM_STREAM_PLAYBACK,
                                 0);
        if (io_result != 0) {
            self->device_handle = NULL;
            return BLT_FAILURE;
        }
        break;

      case BLT_ALSA_OUTPUT_STATE_OPEN:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        return BLT_FAILURE;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_OPEN);

    return BLT_SUCCESS;
}
コード例 #4
0
ファイル: BltAlsaOutput.c プロジェクト: MattLeMay/Bluetune
/*----------------------------------------------------------------------
|    AlsaOutput_Unprepare
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Unprepare(AlsaOutput* self)
{
    BLT_Result result;

    ATX_LOG_FINER("unpreparing output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        break;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* drain any pending samples */
        result = AlsaOutput_Drain(self);
        if (BLT_FAILED(result)) return result;
        
        /* update the state */
        AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);
        break;
    }

    return BLT_SUCCESS;
}
コード例 #5
0
/*----------------------------------------------------------------------
|    AlsaOutput_Reset
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Reset(AlsaOutput* self)
{
    ATX_LOG_FINER("resetting output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        return BLT_SUCCESS;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        ATX_LOG_FINER("snd_pcm_drop");
        snd_pcm_drop(self->device_handle);
        AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);
        break;
    }

    return BLT_SUCCESS;
}
コード例 #6
0
/*----------------------------------------------------------------------
|    AlsaOutput_Unprepare
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Unprepare(AlsaOutput* self)
{
    ATX_LOG_FINER("unpreparing output");

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
      case BLT_ALSA_OUTPUT_STATE_OPEN:
      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
        /* ignore */
        break;

      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* drain any pending samples */
        ATX_LOG_FINER("snd_pcm_drain");
        snd_pcm_drain(self->device_handle);
        
        /* update the state */
        AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);
        break;
    }

    return BLT_SUCCESS;
}
コード例 #7
0
/*----------------------------------------------------------------------
|    AlsaOutput_Configure
+---------------------------------------------------------------------*/
static BLT_Result
AlsaOutput_Configure(AlsaOutput*             self, 
                     const BLT_PcmMediaType* format)
{
    snd_pcm_hw_params_t* hw_params;
    snd_pcm_sw_params_t* sw_params;
    unsigned int         rate = format->sample_rate;
    unsigned int         buffer_time = BLT_ALSA_DEFAULT_BUFFER_TIME;
    snd_pcm_uframes_t    buffer_size = 0;
    snd_pcm_uframes_t    period_size = BLT_ALSA_DEFAULT_PERIOD_SIZE;
    snd_pcm_format_t     pcm_format_id = SND_PCM_FORMAT_UNKNOWN;
    int                  ior;
    BLT_Result           result;

    switch (self->state) {
      case BLT_ALSA_OUTPUT_STATE_CLOSED:
        /* first, we need to open the device */
        result = AlsaOutput_Open(self);
        if (BLT_FAILED(result)) return result;

        /* FALLTHROUGH */

      case BLT_ALSA_OUTPUT_STATE_CONFIGURED:
      case BLT_ALSA_OUTPUT_STATE_PREPARED:
        /* check to see if the format has changed */
        if (format->sample_rate     != self->media_type.sample_rate   ||
            format->channel_count   != self->media_type.channel_count ||
            format->bits_per_sample != self->media_type.bits_per_sample) {
            /* new format */

            /* check the format */
            if (format->sample_rate     == 0 ||
                format->channel_count   == 0 ||
                format->bits_per_sample == 0) {
                return BLT_ERROR_INVALID_MEDIA_FORMAT;
            }
        
            /* unprepare (forget current settings) */
            result = AlsaOutput_Unprepare(self);
            if (BLT_FAILED(result)) return result;
        } else {
            /* same format, do nothing */
            return BLT_SUCCESS;
        }
        
        /* FALLTHROUGH */

      case BLT_ALSA_OUTPUT_STATE_OPEN:
        /* configure the device with the new format */
        ATX_LOG_FINER("configuring ALSA device");

        /* copy the format */
        self->media_type = *format;

        ATX_LOG_FINE_3("new format: sr=%d, ch=%d, bps=%d",
                       format->sample_rate,
                       format->channel_count,
                       format->bits_per_sample);

        /* allocate a new blank configuration */
        snd_pcm_hw_params_alloca_no_assert(&hw_params);
        snd_pcm_hw_params_any(self->device_handle, hw_params);

        /* use interleaved access */
        ior = snd_pcm_hw_params_set_access(self->device_handle, hw_params, 
                                           SND_PCM_ACCESS_RW_INTERLEAVED);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_access failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the sample rate */
        ior = snd_pcm_hw_params_set_rate_near(self->device_handle, 
                                              hw_params, 
                                              &rate, NULL);
        if (ior != 0) {
            ATX_LOG_WARNING_3("snd_pcm_hw_params_set_rate_near(%d) failed (%d:%s)", rate, ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the number of channels */
        ior = snd_pcm_hw_params_set_channels(self->device_handle, 
                                             hw_params,
                                             format->channel_count);
        if (ior != 0) {
            ATX_LOG_WARNING_3("snd_pcm_hw_params_set_channels(%d) failed (%d:%s)", format->channel_count, ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the sample format */
        switch (format->sample_format) {
        	case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_LE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_S8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_S16_LE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_S24_3LE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_S32_LE;  break;
        		}
        		break;
        		
        	case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_LE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_U8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_U16_LE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_U24_3LE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_U32_LE;  break;
        		}
        		break;

        	case BLT_PCM_SAMPLE_FORMAT_FLOAT_LE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_FLOAT_LE");
        		switch (format->bits_per_sample) {
        			case 32: pcm_format_id = SND_PCM_FORMAT_FLOAT_LE; break;
        		}
        		break;

        	case BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_BE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_S8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_S16_BE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_S24_3BE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_S32_BE;  break;
        		}
        		break;
        		
        	case BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_UNSIGNED_INT_BE");
        		switch (format->bits_per_sample) {
        			case  8: pcm_format_id = SND_PCM_FORMAT_U8;      break;
        			case 16: pcm_format_id = SND_PCM_FORMAT_U16_BE;  break;
        			case 24: pcm_format_id = SND_PCM_FORMAT_U24_3BE; break;
        			case 32: pcm_format_id = SND_PCM_FORMAT_U32_BE;  break;
        		}
        		break;

        	case BLT_PCM_SAMPLE_FORMAT_FLOAT_BE:
                ATX_LOG_FINE("sample format is BLT_PCM_SAMPLE_FORMAT_FLOAT_LE");
        		switch (format->bits_per_sample) {
        			case 32: pcm_format_id = SND_PCM_FORMAT_FLOAT_BE; break;
        		}
        		break;
        }

        if (pcm_format_id == SND_PCM_FORMAT_UNKNOWN) {
            return BLT_ERROR_INVALID_MEDIA_TYPE;
        }
        ior = snd_pcm_hw_params_set_format(self->device_handle, 
                                           hw_params,
                                           pcm_format_id);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_format() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* set the period size */
        ior = snd_pcm_hw_params_set_period_size_near(self->device_handle, 
                                                     hw_params,
                                                     &period_size,
                                                     NULL);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_period_size_near() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }
        
                                                
        /* set the buffer time (duration) */
        ior = snd_pcm_hw_params_set_buffer_time_near(self->device_handle,
                                                     hw_params, 
                                                     &buffer_time,
                                                     NULL);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params_set_buffer_time_near() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* get the actual buffer size */
        snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);

        /* activate this configuration */
        ior = snd_pcm_hw_params(self->device_handle, hw_params);
        if (ior != 0) {
            ATX_LOG_WARNING_2("snd_pcm_hw_params() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* configure the software parameters */
        snd_pcm_sw_params_alloca_no_assert(&sw_params);
        snd_pcm_sw_params_current(self->device_handle, sw_params);

        /* set the start threshold to 1/2 the buffer size */
        snd_pcm_sw_params_set_start_threshold(self->device_handle, 
                                              sw_params, 
                                              buffer_size/2);

        /* set the buffer alignment */
        /* NOTE: this call is now obsolete */
        /* snd_pcm_sw_params_set_xfer_align(self->device_handle, sw_params, 1); */

        /* activate the sofware parameters */
        ior = snd_pcm_sw_params(self->device_handle, sw_params);
        if (ior != 0) {
            ATX_LOG_SEVERE_2("snd_pcm_sw_params() failed (%d:%s)", ior, snd_strerror(ior));
            return BLT_FAILURE;
        }

        /* print status info */
        {
            snd_pcm_uframes_t val;
            ATX_LOG_FINER_1("sample type = %x", pcm_format_id);
            if (rate != format->sample_rate) {
                ATX_LOG_FINER_1("actual sample = %d", rate);
            }
            ATX_LOG_FINER_1("actual buffer time = %d", (int)buffer_time);
            ATX_LOG_FINER_1("buffer size = %d", (int)buffer_size); 
            snd_pcm_sw_params_get_start_threshold(sw_params, &val);
            ATX_LOG_FINER_1("start threshold = %d", (int)val); 
            snd_pcm_sw_params_get_stop_threshold(sw_params, &val);
            ATX_LOG_FINER_1("stop threshold = %d", (int)val); 
            snd_pcm_hw_params_get_period_size(hw_params, &val, NULL);
            ATX_LOG_FINER_1("period size = %d", (int)val);
        }

        break;
    }

    /* update the state */
    AlsaOutput_SetState(self, BLT_ALSA_OUTPUT_STATE_CONFIGURED);

    return BLT_SUCCESS;
}