/* trigger callback */ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; int err = 0; audio_info(" .. IN\n"); switch (cmd) { case SNDRV_PCM_TRIGGER_START: audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n", alsa_stream->running); if (!alsa_stream->running) { err = bcm2835_audio_start(alsa_stream); if (!err) { alsa_stream->pcm_indirect.hw_io = alsa_stream->pcm_indirect.hw_data = bytes_to_frames(runtime, alsa_stream->pos); substream->ops->ack(substream); alsa_stream->running = 1; alsa_stream->draining = 1; } else { audio_error(" Failed to START alsa device (%d)\n", err); } } break; case SNDRV_PCM_TRIGGER_STOP: audio_debug ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n", alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING); if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { audio_info("DRAINING\n"); alsa_stream->draining = 1; } else { audio_info("DROPPING\n"); alsa_stream->draining = 0; } if (alsa_stream->running) { err = bcm2835_audio_stop(alsa_stream); if (err != 0) audio_error(" Failed to STOP alsa device (%d)\n", err); alsa_stream->running = 0; } break; default: err = -EINVAL; } audio_info(" .. OUT\n"); return err; }
/****************************************************************************** * function : Ai -> Ao(with fade in/out and volume adjust) ******************************************************************************/ HI_S32 unidoli_audio_service_config(AUDIO_DEV AiDev, AUDIO_DEV AoDev, AUDIO_SAMPLE_RATE_E sample_rast, int num_perfrm) { HI_S32 s32Ret = HI_FAILURE; AIO_ATTR_S stAioAttr; stAioAttr.enSamplerate = sample_rast; stAioAttr.enBitwidth = AUDIO_BIT_WIDTH_16; stAioAttr.enWorkmode = AIO_MODE_I2S_MASTER; stAioAttr.enSoundmode = AUDIO_SOUND_MODE_MONO; stAioAttr.u32EXFlag = 0; stAioAttr.u32FrmNum = 30; stAioAttr.u32PtNumPerFrm = num_perfrm; stAioAttr.u32ChnCnt = 1; stAioAttr.u32ClkSel = 0; /* config audio codec */ /*** INNER AUDIO CODEC ***/ s32Ret = unidoli_codec_config_audio(stAioAttr.enSamplerate); if (HI_SUCCESS != s32Ret) { printf("%s:SAMPLE_INNER_CODEC_CfgAudio failed\n", __FUNCTION__); return s32Ret; } /* enable AI channle */ HI_S32 s32AiChnCnt = stAioAttr.u32ChnCnt; s32Ret = unidoli_start_ai(AiDev, s32AiChnCnt, &stAioAttr, NULL, 0); if (s32Ret != HI_SUCCESS) { audio_debug(s32Ret); return s32Ret; } HI_S32 s32AoChnCnt = stAioAttr.u32ChnCnt; s32Ret = unidoli_start_ao(AoDev, s32AoChnCnt, &stAioAttr, NULL , 0); if (s32Ret != HI_SUCCESS) { audio_debug(s32Ret); return s32Ret; } return s32Ret; }
/* prepare callback */ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) { struct bcm2835_chip *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct bcm2835_alsa_stream *alsa_stream = runtime->private_data; int channels; int err; audio_info(" .. IN\n"); if (mutex_lock_interruptible(&chip->audio_mutex)) return -EINTR; /* notify the vchiq that it should enter spdif passthrough mode by * setting channels=0 (see * https://github.com/raspberrypi/linux/issues/528) */ if (chip->spdif_status & IEC958_AES0_NONAUDIO) channels = 0; else channels = alsa_stream->channels; err = bcm2835_audio_set_params(alsa_stream, channels, alsa_stream->params_rate, alsa_stream->pcm_format_width); if (err < 0) { audio_error(" error setting hw params\n"); } bcm2835_audio_setup(alsa_stream); /* in preparation of the stream, set the controls (volume level) of the stream */ bcm2835_audio_set_ctls(alsa_stream->chip); memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); alsa_stream->pcm_indirect.hw_buffer_size = alsa_stream->pcm_indirect.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); alsa_stream->pos = 0; audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", alsa_stream->buffer_size, alsa_stream->period_size, alsa_stream->pos, runtime->frame_bits); mutex_unlock(&chip->audio_mutex); audio_info(" .. OUT\n"); return 0; }
/* pointer callback */ static snd_pcm_uframes_t snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0, frames_to_bytes(runtime, runtime->status->hw_ptr), frames_to_bytes(runtime, runtime->control->appl_ptr), alsa_stream->pos); audio_info(" .. OUT\n"); return bytes_to_frames(runtime, alsa_stream->pos); }
static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id) { bcm2835_alsa_stream_t *alsa_stream = (bcm2835_alsa_stream_t *) dev_id; uint32_t consumed = 0; int new_period = 0; audio_info(" .. IN\n"); audio_info("alsa_stream=%p substream=%p\n", alsa_stream, alsa_stream ? alsa_stream->substream : 0); if (alsa_stream->open) consumed = bcm2835_audio_retrieve_buffers(alsa_stream); /* We get called only if playback was triggered, So, the number of buffers we retrieve in * each iteration are the buffers that have been played out already */ if (alsa_stream->period_size) { if ((alsa_stream->pos / alsa_stream->period_size) != ((alsa_stream->pos + consumed) / alsa_stream->period_size)) new_period = 1; } audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n", alsa_stream->pos, consumed, alsa_stream->buffer_size, (int)(alsa_stream->period_size*alsa_stream->substream->runtime->periods), frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr), new_period); if (alsa_stream->buffer_size) { alsa_stream->pos += consumed &~ (1<<30); alsa_stream->pos %= alsa_stream->buffer_size; } if (alsa_stream->substream) { if (new_period) snd_pcm_period_elapsed(alsa_stream->substream); } else { audio_warning(" unexpected NULL substream\n"); } audio_info(" .. OUT\n"); return IRQ_HANDLED; }
/* prepare callback */ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream); alsa_stream->period_size = snd_pcm_lib_period_bytes(substream); alsa_stream->pos = 0; audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n", alsa_stream->buffer_size, alsa_stream->period_size, alsa_stream->pos, runtime->frame_bits); audio_info(" .. OUT\n"); return 0; }
static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count) { int ret; struct snd_pcm_runtime *runtime = substream->runtime; bcm2835_alsa_stream_t *alsa_stream = runtime->private_data; audio_info(" .. IN\n"); audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n", frames_to_bytes(runtime, count), frames_to_bytes(runtime, runtime-> status-> hw_ptr), frames_to_bytes(runtime, runtime->control->appl_ptr), alsa_stream->pos); ret = bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count), src); audio_info(" .. OUT\n"); return ret; }