[開發記錄] 函式庫調用 - 使用ALSA進行音訊資料擷取 之其三

在使用ALSA的API進行聲音擷取,capture部分似乎是沒問題的,但在進行playback時,產生了under run的狀況,

OVERRUN :一般是在進行Capture時,硬體buffer已滿,卻未即時取出資料,使得該筆資料丟失,而產生錯誤;

UNDERRUN :是只在進行playback時,硬體buffer已全數輸出,而來不及補充後續資料,使得資料斷掉;

以上兩種情況,都稱為 XRUN ,在下一筆資料傳送之前,須先使用 snd_pcm_prepare (handle); 進行硬體的初始化,


目前測試時產生的 under run狀況仍未查明,持續研究....


由於使用一般方式,無法即時取得硬體狀況,須在下一筆資料處理時,才會回應出錯誤資訊,無法及時修正,

嘗試使用 Interrupt-Drive 方式,參考以下代碼:


	#include <stdio.h>
	#include <stdlib.h>
	#include <errno.h>
	#include <poll.h>
	#include <alsa/asoundlib.h>

	snd_pcm_t *playback_handle;
	short buf[4096];

	int
	playback_callback (snd_pcm_sframes_t nframes)
	{
		int err;

		printf ("playback callback called with %u frames\n", nframes);

		/* ... fill buf with data ... */

		if ((err = snd_pcm_writei (playback_handle, buf, nframes)) < 0) {
			fprintf (stderr, "write failed (%s)\n", snd_strerror (err));
		}

		return err;
	}

	main (int argc, char *argv[])
	{

		snd_pcm_hw_params_t *hw_params;
		snd_pcm_sw_params_t *sw_params;
		snd_pcm_sframes_t frames_to_deliver;
		int nfds;
		int err;
		struct pollfd *pfds;

		if ((err = snd_pcm_open (&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
			fprintf (stderr, "cannot open audio device %s (%s)\n",
				 argv[1],
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
			fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
			fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
			fprintf (stderr, "cannot set access type (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0) {
			fprintf (stderr, "cannot set sample format (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, 44100, 0)) < 0) {
			fprintf (stderr, "cannot set sample rate (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 2)) < 0) {
			fprintf (stderr, "cannot set channel count (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
			fprintf (stderr, "cannot set parameters (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		snd_pcm_hw_params_free (hw_params);

		/* tell ALSA to wake us up whenever 4096 or more frames
		   of playback data can be delivered. Also, tell
		   ALSA that we'll start the device ourselves.
		*/

		if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
			fprintf (stderr, "cannot allocate software parameters structure (%s)\n",
				 snd_strerror (err));
			exit (1);
		}
		if ((err = snd_pcm_sw_params_current (playback_handle, sw_params)) < 0) {
			fprintf (stderr, "cannot initialize software parameters structure (%s)\n",
				 snd_strerror (err));
			exit (1);
		}
		if ((err = snd_pcm_sw_params_set_avail_min (playback_handle, sw_params, 4096)) < 0) {
			fprintf (stderr, "cannot set minimum available count (%s)\n",
				 snd_strerror (err));
			exit (1);
		}
		if ((err = snd_pcm_sw_params_set_start_threshold (playback_handle, sw_params, 0U)) < 0) {
			fprintf (stderr, "cannot set start mode (%s)\n",
				 snd_strerror (err));
			exit (1);
		}
		if ((err = snd_pcm_sw_params (playback_handle, sw_params)) < 0) {
			fprintf (stderr, "cannot set software parameters (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		/* the interface will interrupt the kernel every 4096 frames, and ALSA
		   will wake up this program very soon after that.
		*/

		if ((err = snd_pcm_prepare (playback_handle)) < 0) {
			fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
				 snd_strerror (err));
			exit (1);
		}

		while (1) {

			/* wait till the interface is ready for data, or 1 second
			   has elapsed.
			*/

			if ((err = snd_pcm_wait (playback_handle, 1000)) < 0) {
			        fprintf (stderr, "poll failed (%s)\n", strerror (errno));
			        break;
			}

			/* find out how much space is available for playback data */

			if ((frames_to_deliver = snd_pcm_avail_update (playback_handle)) < 0) {
				if (frames_to_deliver == -EPIPE) {
					fprintf (stderr, "an xrun occured\n");
					break;
				} else {
					fprintf (stderr, "unknown ALSA avail update return value (%d)\n",
						 frames_to_deliver);
					break;
				}
			}

			frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver;

			/* deliver the data */

			if (playback_callback (frames_to_deliver) != frames_to_deliver) {
			        fprintf (stderr, "playback callback failed\n");
				break;
			}
		}
		snd_pcm_close (playback_handle);
		exit (0);
	}


使用此方式,仍在播放時產生under run狀況,與之前發生相同狀況,

目前仍不清楚播放如何解決,目前重點在截取聲音資料,目前確認錄製後的音訊,使用aplay可正常播放,播放程式的測試目前只能先暫停,後續在研究...


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值