示例#1
0
// Write writes given PCM data.
// Returns wrote value is total bytes was written.
func (handle *Handle) Write(buf []byte) (wrote int, err error) {
	frames := len(buf) / handle.SampleSize() / handle.Channels
	w := C.snd_pcm_writei(handle.cHandle, unsafe.Pointer(&buf[0]), C.snd_pcm_uframes_t(frames))

	// Underrun? Retry.
	if w == -C.EPIPE {
		C.snd_pcm_prepare(handle.cHandle)
		w = C.snd_pcm_writei(handle.cHandle, unsafe.Pointer(&buf[0]), C.snd_pcm_uframes_t(frames))
	}

	if w < 0 {
		return 0, fmt.Errorf("Write failed. %s", strError(_Ctype_int(w)))
	}

	wrote = int(w)
	wrote *= handle.FrameSize()

	return wrote, nil
}
示例#2
0
// Read reads samples into a buffer and returns the amount read.
func (c *CaptureDevice) Read(buffer interface{}) (samples int, err error) {
	bufferType := reflect.TypeOf(buffer)
	if !(bufferType.Kind() == reflect.Array ||
		bufferType.Kind() == reflect.Slice) {
		return 0, errors.New("Read requires an array type")
	}

	sizeError := errors.New("Read requires a matching sample size")
	switch bufferType.Elem().Kind() {
	case reflect.Int8:
		if c.formatSampleSize() != 1 {
			return 0, sizeError
		}
	case reflect.Int16:
		if c.formatSampleSize() != 2 {
			return 0, sizeError
		}
	case reflect.Int32, reflect.Float32:
		if c.formatSampleSize() != 4 {
			return 0, sizeError
		}
	case reflect.Float64:
		if c.formatSampleSize() != 8 {
			return 0, sizeError
		}
	default:
		return 0, errors.New("Read does not support this format")
	}

	val := reflect.ValueOf(buffer)
	length := val.Len()
	sliceData := val.Slice(0, length)

	var frames = C.snd_pcm_uframes_t(length / c.Channels)
	bufPtr := unsafe.Pointer(sliceData.Index(0).Addr().Pointer())

	ret := C.snd_pcm_readi(c.h, bufPtr, frames)

	if ret == -C.EPIPE {
		C.snd_pcm_prepare(c.h)
		return 0, ErrOverrun
	} else if ret < 0 {
		return 0, createError("read error", C.int(ret))
	}
	samples = int(ret) * c.Channels
	return
}
示例#3
0
文件: alsa.go 项目: terual/alsa-go
// Skip certain number of frames
func (handle *Handle) SkipFrames(frames int) (int, error) {

	// Get safe count of frames which can be forwarded.
	var framesForwardable C.snd_pcm_sframes_t
	framesForwardable = C.snd_pcm_forwardable(handle.cHandle)
	if framesForwardable < 0 {
		return 0, errors.New(fmt.Sprintf("Retrieving forwardable frames failed. %s", strError(_Ctype_int(framesForwardable))))
	}

	if int(_Ctype_int(framesForwardable)) < frames {
		frames = int(_Ctype_int(framesForwardable))
	}

	// Move application frame position forward.
	var framesForwarded C.snd_pcm_sframes_t
	framesForwarded = C.snd_pcm_forward(handle.cHandle, C.snd_pcm_uframes_t(frames))
	if framesForwarded < 0 {
		return 0, errors.New(fmt.Sprintf("Cannot forward frames. %s", strError(_Ctype_int(framesForwarded))))
	}

	return int(_Ctype_int(framesForwarded)), nil
}
示例#4
0
文件: alsa.go 项目: terual/alsa-go
// ApplyHwParams changes ALSA hardware parameters for the current stream.
func (handle *Handle) ApplyHwParams() error {
	var cHwParams *C.snd_pcm_hw_params_t

	err := C.snd_pcm_hw_params_malloc(&cHwParams)
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot allocate hardware parameter structure. %s",
			strError(err)))
	}

	err = C.snd_pcm_hw_params_any(handle.cHandle, cHwParams)
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot initialize hardware parameter structure. %s",
			strError(err)))
	}

	err = C.snd_pcm_hw_params_set_access(handle.cHandle, cHwParams, C.SND_PCM_ACCESS_RW_INTERLEAVED)
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot set access type. %s",
			strError(err)))
	}

	err = C.snd_pcm_hw_params_set_format(handle.cHandle, cHwParams, C.snd_pcm_format_t(handle.SampleFormat))
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot set sample format. %s",
			strError(err)))
	}

	var cSampleRate _Ctype_uint = _Ctype_uint(handle.SampleRate)
	err = C.snd_pcm_hw_params_set_rate_near(handle.cHandle, cHwParams, &cSampleRate, nil)
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot set sample rate. %s",
			strError(err)))
	}

	err = C.snd_pcm_hw_params_set_channels(handle.cHandle, cHwParams, _Ctype_uint(handle.Channels))
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot set number of channels. %s",
			strError(err)))
	}

	if handle.Periods > 0 {
		// Set number of periods. Periods used to be called fragments.
		/*err = C.snd_pcm_hw_params_set_periods(handle.cHandle, cHwParams, _Ctype_uint(handle.Periods), 0)
		if err < 0 {
			return os.NewError(fmt.Sprintf("Cannot set number of periods. %s",
				strError(err)))
		}*/

		var cPeriods _Ctype_uint = _Ctype_uint(handle.Periods)
		var cDir _Ctype_int = 0 // Exact value is <,=,> the returned one following dir (-1,0,1)
		err = C.snd_pcm_hw_params_set_periods_near(handle.cHandle, cHwParams, &cPeriods, &cDir)
		if err < 0 {
			return errors.New(fmt.Sprintf("Cannot set number of periods. %s",
				strError(err)))
		}
	}

	if handle.Buffersize > 0 {
		// Set buffer size (in frames). The resulting latency is given by
		// latency = periodsize * periods / (rate * bytes_per_frame)
		/*err = C.snd_pcm_hw_params_set_buffer_size(handle.cHandle, cHwParams, _Ctypedef_snd_pcm_uframes_t(handle.Buffersize))
		if err < 0 {
			return os.NewError(fmt.Sprintf("Cannot set buffersize. %s",
				strError(err)))
		}*/

		var cBuffersize C.snd_pcm_uframes_t = C.snd_pcm_uframes_t(handle.Buffersize)
		err = C.snd_pcm_hw_params_set_buffer_size_near(handle.cHandle, cHwParams, &cBuffersize)
		if err < 0 {
			return errors.New(fmt.Sprintf("Cannot set buffersize. %s",
				strError(err)))
		}

	}

	// Drain current data and make sure we aren't underrun.
	C.snd_pcm_drain(handle.cHandle)

	err = C.snd_pcm_hw_params(handle.cHandle, cHwParams)
	if err < 0 {
		return errors.New(fmt.Sprintf("Cannot set hardware parameters. %s",
			strError(err)))
	}

	C.snd_pcm_hw_params_free(cHwParams)

	return nil
}
示例#5
0
func (d *device) createDevice(deviceName string, channels int, format Format, rate int, playback bool, bufferParams BufferParams) (err error) {
	deviceCString := C.CString(deviceName)
	defer C.free(unsafe.Pointer(deviceCString))
	var ret C.int
	if playback {
		ret = C.snd_pcm_open(&d.h, deviceCString, C.SND_PCM_STREAM_PLAYBACK, 0)
	} else {
		ret = C.snd_pcm_open(&d.h, deviceCString, C.SND_PCM_STREAM_CAPTURE, 0)
	}
	if ret < 0 {
		return fmt.Errorf("could not open ALSA device %s", deviceName)
	}
	runtime.SetFinalizer(d, (*device).Close)
	var hwParams *C.snd_pcm_hw_params_t
	ret = C.snd_pcm_hw_params_malloc(&hwParams)
	if ret < 0 {
		return createError("could not alloc hw params", ret)
	}
	defer C.snd_pcm_hw_params_free(hwParams)
	ret = C.snd_pcm_hw_params_any(d.h, hwParams)
	if ret < 0 {
		return createError("could not set default hw params", ret)
	}
	ret = C.snd_pcm_hw_params_set_access(d.h, hwParams, C.SND_PCM_ACCESS_RW_INTERLEAVED)
	if ret < 0 {
		return createError("could not set access params", ret)
	}
	ret = C.snd_pcm_hw_params_set_format(d.h, hwParams, C.snd_pcm_format_t(format))
	if ret < 0 {
		return createError("could not set format params", ret)
	}
	ret = C.snd_pcm_hw_params_set_channels(d.h, hwParams, C.uint(channels))
	if ret < 0 {
		return createError("could not set channels params", ret)
	}
	ret = C.snd_pcm_hw_params_set_rate(d.h, hwParams, C.uint(rate), 0)
	if ret < 0 {
		return createError("could not set rate params", ret)
	}
	var bufferSize = C.snd_pcm_uframes_t(bufferParams.BufferFrames)
	if bufferParams.BufferFrames == 0 {
		// Default buffer size: max buffer size
		ret = C.snd_pcm_hw_params_get_buffer_size_max(hwParams, &bufferSize)
		if ret < 0 {
			return createError("could not get buffer size", ret)
		}
	}
	ret = C.snd_pcm_hw_params_set_buffer_size_near(d.h, hwParams, &bufferSize)
	if ret < 0 {
		return createError("could not set buffer size", ret)
	}
	// Default period size: 1/8 of a second
	var periodFrames = C.snd_pcm_uframes_t(rate / 8)
	if bufferParams.PeriodFrames > 0 {
		periodFrames = C.snd_pcm_uframes_t(bufferParams.PeriodFrames)
	} else if bufferParams.Periods > 0 {
		periodFrames = C.snd_pcm_uframes_t(int(bufferSize) / bufferParams.Periods)
	}
	ret = C.snd_pcm_hw_params_set_period_size_near(d.h, hwParams, &periodFrames, nil)
	if ret < 0 {
		return createError("could not set period size", ret)
	}
	var periods = C.uint(0)
	ret = C.snd_pcm_hw_params_get_periods(hwParams, &periods, nil)
	if ret < 0 {
		return createError("could not get periods", ret)
	}
	ret = C.snd_pcm_hw_params(d.h, hwParams)
	if ret < 0 {
		return createError("could not set hw params", ret)
	}
	d.frames = int(periodFrames)
	d.Channels = channels
	d.Format = format
	d.Rate = rate
	d.BufferParams.BufferFrames = int(bufferSize)
	d.BufferParams.PeriodFrames = int(periodFrames)
	d.BufferParams.Periods = int(periods)
	return
}