From patchwork Fri Feb 6 16:15:59 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Cussins X-Patchwork-Id: 5793031 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 5D1B29F336 for ; Fri, 6 Feb 2015 16:16:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5ACB620172 for ; Fri, 6 Feb 2015 16:16:32 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 9D9212017D for ; Fri, 6 Feb 2015 16:16:30 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 27A1926531F; Fri, 6 Feb 2015 17:16:29 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, FREEMAIL_FROM,SUBJ_OBFU_PUNCT_MANY,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 8B11C2651A4; Fri, 6 Feb 2015 17:16:20 +0100 (CET) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 129D92651EC; Fri, 6 Feb 2015 17:16:19 +0100 (CET) Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) by alsa0.perex.cz (Postfix) with ESMTP id 741212605E8 for ; Fri, 6 Feb 2015 17:16:13 +0100 (CET) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id 01B8620AD6 for ; Fri, 6 Feb 2015 11:16:12 -0500 (EST) Received: from frontend1 ([10.202.2.160]) by compute1.internal (MEProxy); Fri, 06 Feb 2015 11:16:13 -0500 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=eml.cc; h= x-sasl-enc:from:to:cc:subject:date:message-id; s=mesmtp; bh=Fgv8 v2oU5RPVsUhNByfIV0gT+BQ=; b=f+9+U3SXmp84cSlxqLBMAsCZO3k2QVXZqKbT MTRUy829GcOGnbsZGbM8P1dB3lflhlXC5U3SvmaUzQkU5umWasQPQi416wFLEDK0 kiNor/A7nODwnlk8KGvWbjQIGuTX3kkG4R6md/jllVXIA4WhOcfIEuk5842dymqi /SCVSqU= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=x-sasl-enc:from:to:cc:subject:date :message-id; s=smtpout; bh=Fgv8v2oU5RPVsUhNByfIV0gT+BQ=; b=MMxfE aAD3OssO+srUM+kvMJAYvrhBT7uTzrUCXD1719Sh0FvCrzX42NUV6ZONBu3g1zda cVcdmb1ebsXuDeW2uA0OuZPByNiDupZ+ildx8dZOu5vVNjHXM3tHgWMKWEboWxr6 am5roRatF7LRZmU/eo5nB/XWP1oGzV2+EpCfZs= X-Sasl-enc: cFwL1vYA42AirRRhHe//lyFQkc/1wrWHf5YLs2P/HN7o 1423239372 Received: from PC816.linn.co.uk (unknown [195.59.102.251]) by mail.messagingengine.com (Postfix) with ESMTPA id 41B1FC0028A; Fri, 6 Feb 2015 11:16:12 -0500 (EST) From: Tim Cussins To: alsa-devel@alsa-project.org Date: Fri, 6 Feb 2015 16:15:59 +0000 Message-Id: <1423239361-17655-1-git-send-email-timcussins@eml.cc> X-Mailer: git-send-email 1.9.1 Cc: Tim Cussins Subject: [alsa-devel] [PATCH v3 alsa-lib 1/3] snd_pcm_start_at and friends. X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP Upcoming audio hardware has the ability to begin playback when the value of a high-precision free-running counter matches some programmable value. This patch exposes such capability in a general way, allowing for several clock sources, including both system clocks and audio hardware clocks. We define 3 new methods that operate on a snd_pcm_t, and 1 that operates on a snd_pcm_status_t. - snd_pcm_start_at() allows client code to delegate the starting of the stream to the kernel. - snd_pcm_start_at_abort() allows client code to cancel a previous call to snd_pcm_start_at(). - snd_pcm_start_at_gettime() allows client code to query the current time for a given clock. - snd_pcm_status_get_startat_state() allows client code to extract information about any pending start_at timer from a snd_pcm_status_t object. We define a new enum: snd_pcm_startat_clock_type_t, which reinforces a clean boundary between the capabilities of the timestamping system and the start_at system. The clock and audio hw sources are grouped together because the difference is irrelevant to the use of snd_pcm_start_at(). Signed-off-by: Tim Cussins diff --git a/include/pcm.h b/include/pcm.h index 0655e7f..4f4834b 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -330,6 +330,17 @@ typedef enum _snd_pcm_tstamp_type { SND_PCM_TSTAMP_TYPE_LAST = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW, } snd_pcm_tstamp_type_t; +/** PCM start_at clock types */ +typedef enum _snd_pcm_startat_clock_type { + /** POSIX CLOCK_REALTIME equivalent */ + SND_PCM_STARTAT_CLOCK_TYPE_GETTIMEOFDAY = 0, + /** POSIX CLOCK_MONOTONIC equivalent */ + SND_PCM_STARTAT_CLOCK_TYPE_MONOTONIC, + /** Default link clock */ + SND_PCM_STARTAT_CLOCK_TYPE_LINK, + SND_PCM_STARTAT_CLOCK_TYPE_LAST = SND_PCM_STARTAT_CLOCK_TYPE_LINK, +} snd_pcm_startat_clock_type_t; + /** Unsigned frames quantity */ typedef unsigned long snd_pcm_uframes_t; /** Signed frames quantity */ @@ -478,6 +489,9 @@ int snd_pcm_prepare(snd_pcm_t *pcm); int snd_pcm_reset(snd_pcm_t *pcm); int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status); int snd_pcm_start(snd_pcm_t *pcm); +int snd_pcm_start_at(snd_pcm_t *pcm, snd_pcm_startat_clock_type_t clock_type, const snd_htimestamp_t* start_time); +int snd_pcm_start_at_abort(snd_pcm_t *pcm); +int snd_pcm_start_at_gettime(snd_pcm_t *pcm, snd_pcm_startat_clock_type_t clock_type, snd_htimestamp_t* current_time); int snd_pcm_drop(snd_pcm_t *pcm); int snd_pcm_drain(snd_pcm_t *pcm); int snd_pcm_pause(snd_pcm_t *pcm, int enable); @@ -984,6 +998,7 @@ snd_pcm_sframes_t snd_pcm_status_get_delay(const snd_pcm_status_t *obj); snd_pcm_uframes_t snd_pcm_status_get_avail(const snd_pcm_status_t *obj); snd_pcm_uframes_t snd_pcm_status_get_avail_max(const snd_pcm_status_t *obj); snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj); +void snd_pcm_status_get_startat_state(const snd_pcm_status_t *obj, int *pending, snd_pcm_startat_clock_type_t *clock_type, snd_htimestamp_t *start_time); /** \} */ diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index e74e02f..f2cbd8e 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -1085,6 +1085,74 @@ int snd_pcm_start(snd_pcm_t *pcm) } /** + * \brief Start a PCM at a specified point in the future + * \param pcm PCM handle + * \param clock_type Specifies the start_at clock with which to interpret \p start_time + * \param start_time Absolute time at which to start the stream + * \return 0 on success otherwise a negative error code + * \retval -ENOSYS operation not supported for the current timestamp type + * \retval -EINVAL timespec, tstamp_class or tstamp_type is invalid + * \retval -ETIME requested start_time cannot be satisfied + * + * This method is non-blocking: It establishes an appropriate timer in the kernel + * that will start the stream on expiry. + * + * Any pending timer is unconditionally cancelled. + */ +int snd_pcm_start_at(snd_pcm_t *pcm, snd_pcm_startat_clock_type_t clock_type, const snd_htimestamp_t *start_time) +{ + assert(pcm); + assert(start_time); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->fast_ops->start_at) { + return pcm->fast_ops->start_at(pcm->fast_op_arg, clock_type, start_time); + } + return -EINVAL; +} + +/** + * \brief Abort the pending PCM start_at timer + * \param pcm PCM handle + * \return 0 on success otherwise a negative error code + * + * If a start_at timer is pending, it is cancelled. + */ +int snd_pcm_start_at_abort(snd_pcm_t *pcm) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->fast_ops->start_at_abort) { + return pcm->fast_ops->start_at_abort(pcm->fast_op_arg); + } + return -EINVAL; +} + +/** + * \brief Get current time for a given start_at clock + * \param pcm PCM handle + * \param clock_type Start_at clock type e.g. SND_PCM_STARTAT_CLOCK_TYPE_GETTIMEOFDAY + * \return 0 on success otherwise a negative error code + */ +int snd_pcm_start_at_gettime(snd_pcm_t *pcm, snd_pcm_startat_clock_type_t clock_type, snd_htimestamp_t *current_time) +{ + assert(pcm); + if (CHECK_SANITY(! pcm->setup)) { + SNDMSG("PCM not set up"); + return -EIO; + } + if (pcm->fast_ops->start_at_gettime) { + return pcm->fast_ops->start_at_gettime(pcm->fast_op_arg, clock_type, current_time); + } + return -EINVAL; +} + +/** * \brief Stop a PCM dropping pending frames * \param pcm PCM handle * \return 0 on success otherwise a negative error code @@ -6380,6 +6448,20 @@ snd_pcm_uframes_t snd_pcm_status_get_overrange(const snd_pcm_status_t *obj) } /** + * \brief Get status of a pending start_at timer, if any. + * \param pending output param: 1 if start_at timer pending, 0 otherwise + * \param clock_type output param: if pending == 1, is updated with current start_at timer clock_type + * \param start_time output param: if pending == 1, is updated with current start_at timer start_time + */ +void snd_pcm_status_get_startat_state(const snd_pcm_status_t *obj, int *pending, snd_pcm_startat_clock_type_t *clock_type, snd_htimestamp_t *start_time) +{ + assert(obj); + *pending = obj->start_at_pending; + *clock_type = obj->start_at_clock_type; + *start_time = obj->start_at_start_time; +} + +/** * \brief get size of #snd_pcm_info_t * \return size in bytes */