From ce6d1aaf83d0631dcab19be20f2275b4498774a1 Mon Sep 17 00:00:00 2001 From: youenn Date: Wed, 16 Oct 2024 13:21:13 +0200 Subject: [PATCH 1/7] Add algorithms that describe how type/state are assigned/updated, and how they influence audio sessions and audio focus. --- index.bs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/index.bs b/index.bs index 5698eec..df9d9e1 100644 --- a/index.bs +++ b/index.bs @@ -175,6 +175,88 @@ partial interface Navigator { }; +# Audio session algorithms # {#audio-session-algorithms} + +## Update AudioSession's type ## {#audio-session-update-type-algorithm} + +To update the type of |audioSession|, the user agent MUST run the following steps: +1. If |audioSession|.[=AudioSession/[[isTypeBeingApplied]]=] is `true`, abort these steps. +1. Set |audioSession|.[=AudioSession/[[isTypeBeingApplied]]=] to `true`. +1. [=Queue a task=] to run the following steps: + 1. Set |audioSession|.[=AudioSession/[[isTypeBeingApplied]]=] to `false`. + 1. If |audioSession|.[=AudioSession/[[type]]=] is the same as |audioSession|.[=AudioSession/[[appliedType]]=], abort these steps. + 1. Set |audioSession|.[=AudioSession/[[appliedType]]=] to |audioSession|.[=AudioSession/[[type]]=]. + 1. [=Update all AudioSession states=] of |audioSession|'s [=top-level browsing context=] with |audioSession|. + 1. For each |element| of |audioSession|.[=AudioSession/[[elements]]=], [=update an element|update=] |element|. + 1. Let |newType| be the result of [=compute the audio session type|computing the type=] of |audioSession|. + 1. [=In parallel=], change the [=audio session/type=] of |audioSession|'s [=audio session=] to |newType|. + +## Update AudioSession's state ## {#audio-session-update-state-algorithm} + +When an audio session [=audio session/element=] is starting or stopping, the user agent will run steps that change the state of an [=audio session=]. +Changing an [=audio session=]'s [=audio session/state=] to {{AudioSessionState/active}} has consequences, especially if the [=audio session=]'s [=audio session/type=] is an [=exclusive type=]: +* It can [=inactivate=] {{AudioSession}} objects of the [=top-level browsing context=], as defined in the algorithms below. +* It can pause the audio of another tab or another application. + +Conversely, an [=audio session=] [=audio session/state=] can be modified outside of audio session [=audio session/element=] changes, for instance in case an active [=audio session=] is interrupted. +When the user agent observes such a modification, the user agent MUST [=queue a task=] to [=update the state=] of |audioSession|, the {{AudioSession}} object [=tied to=] the modified [=audio session=] with |newState| being the new [=audio session=] [=audio session/state=]. + +To update the state of |audioSession| with |newState|, the user agent MUST run the following steps: +1. Let |isMutatingState| be `true` if |audioSession|.[=AudioSession/[[state]]=] is not |newState| and `false` otherwise. +1. Set |audioSession|.[=AudioSession/[[state]]=] to |newState|. +1. If |newState| is {{AudioSessionState/inactive}}, set |audioSession|.[=AudioSession/[[interruptedElements]]=] to an empty list. +1. For each |element| of |audioSession|.[=AudioSession/[[elements]]=], [=update an element|update=] |element|. +1. If |isMutatingState| is `false`, abort these steps. +1. [=Update all AudioSession states=] of |audioSession|'s [=top-level browsing context=] with |audioSession|. +1. Fire an event named statechange at |audioSession|. + +To inactivate an {{AudioSession}} named |audioSession|, the user agent MUST run the following steps: +1. If |audioSession|.[=AudioSession/[[state]]=] is {{AudioSessionState/inactive}}, abort these steps. +1. Run the following steps [=in parallel=]: + 1. [=Change the state=] of |audioSession|'s [=audio session=] to {{AudioSessionState/inactive}}. + 1. Assert that |audioSession|'s [=audio session=]'s [=audio session/state=] is {{AudioSessionState/inactive}}. + 1. [=Queue a task=] to [=update the state=] of |audioSession| with its [=audio session=]'s [=audio session/state=]. + +To try activating an {{AudioSession}} named |audioSession|, the user agent MUST run the following steps: +1. If |audioSession|.[=AudioSession/[[state]]=] is {{AudioSessionState/active}}, abort these steps. +1. Run the following steps [=in parallel=]: + 1. [=Change the state=] of |audioSession|'s [=audio session=] to {{AudioSessionState/active}}. [=Change the state|Changing the state=] to {{AudioSessionState/active}} can fail, in which case the [=audio session=]'s [=audio session/state=] will either be {{AudioSessionState/inactive}} or {{AudioSessionState/interrupted}}. + 1. [=Queue a task=] to [=update the state=] of |audioSession| with its [=audio session=]'s [=audio session/state=]. + +## Update the selected audio session ## {#audio-session-update-selected-audio-session-algorithm} + +To update the selected audio session of a [=top-level browsing context=] named |context|, the user agent MUST run the following steps: +1. Let |activeAudioSessions| be the list of all the [=audio session|audio sessions=] [=tied to=] {{AudioSession}} objects of |context| and its children in a breadth-first order, that match both constraints: + 1. Its [=audio session/state=] is {{AudioSessionState/active}}. + 1. Its [=audio session/type=] is an [=exclusive type=]. +1. If |activeAudioSessions| is empty, abort these steps. +1. If there is only one [=audio session=] in |activeAudioSessions|, set the [=selected audio session=] to this [=audio session=] and abort these steps. +1. Assert that for any {{AudioSession}} object [=tied to=] an [=audio session=] in |activeAudioSessions|'s named |audioSession|, |audioSession|.[=AudioSession/[[type]]=] is {{AudioSessionType/auto}}. +1. The user agent MAY apply specific heuristics to reorder |activeAudioSessions|. +1. Set the [=selected audio session=] to the first [=audio session=] in |activeAudioSessions|. + +## Other algorithms ## {#audio-session-other-algorithms} + +To update all AudioSession states of a [=top-level browsing context=] named |context| with |updatedAudioSession|, run the following steps: +1. [=Update the selected audio session=] of |context|. +1. Let |updatedType| be the result of [=compute the audio session type|computing the type=] of |updatedAudioSession|. +1. If |updatedType| is not an [=exclusive type=] or |updatedAudioSession|.[=AudioSession/[[state]]=] is not {{AudioSessionState/active}}, abort these steps. +1. Let |audioSessions| be the list of all the {{AudioSession}} objects of |context| and its children in a breadth-first order. +1. For each |audioSession| of |audioSessions| except for |updatedAudioSession|, run the following steps: + 1. If |audioSession|.[=AudioSession/[[state]]=] is not {{AudioSessionState/active}}, abort these steps. + 1. Let |type| be the result of [=compute the audio session type|computing the type=] of |audioSession|. + 1. If |type| is not an [=exclusive type=], abort these steps. + 1. If |type| and |updatedType| are both {{AudioSessionType/auto}}, abort these steps. + 1. [=Inactivate=] |audioSession|. + +To compute the audio session type of |audioSession|, the user agent MUST run the following steps: +1. If |audioSession|.[=AudioSession/[[type]]=] is not {{AudioSessionType/auto}}, return |audioSession|.[=AudioSession/[[type]]=]. +1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/play-and-record}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/play-and-record}}. +1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/playback}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/playback}}. +1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/transient}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/transient}}. +1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/ambient}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/ambient}}. +1. Return {{AudioSessionType/auto}}. + # Privacy considerations # {#privacy} # Security considerations # {#security} From a71e203b78471057dc17022609f4354b40c69594 Mon Sep 17 00:00:00 2001 From: Youenn Fablet Date: Mon, 28 Oct 2024 12:30:37 +0100 Subject: [PATCH 2/7] Add an example of activation failure --- index.bs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/index.bs b/index.bs index df9d9e1..4a63306 100644 --- a/index.bs +++ b/index.bs @@ -223,6 +223,9 @@ To try activating an {{AudioSession}} named |audioSession|, the user 1. [=Change the state=] of |audioSession|'s [=audio session=] to {{AudioSessionState/active}}. [=Change the state|Changing the state=] to {{AudioSessionState/active}} can fail, in which case the [=audio session=]'s [=audio session/state=] will either be {{AudioSessionState/inactive}} or {{AudioSessionState/interrupted}}. 1. [=Queue a task=] to [=update the state=] of |audioSession| with its [=audio session=]'s [=audio session/state=]. +Activating an [=audio session=] can fail for various reasons. +For instance, a web application may try to start playing some audio while a higher priviledge application, like a phone call application, is already playing audio. + ## Update the selected audio session ## {#audio-session-update-selected-audio-session-algorithm} To update the selected audio session of a [=top-level browsing context=] named |context|, the user agent MUST run the following steps: From 0dea19209f22db6fac1ac1057cae5fc9e2ad26aa Mon Sep 17 00:00:00 2001 From: Youenn Fablet Date: Mon, 28 Oct 2024 12:33:10 +0100 Subject: [PATCH 3/7] Beefing up an example for audio session state change --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 4a63306..6f758fd 100644 --- a/index.bs +++ b/index.bs @@ -198,7 +198,7 @@ Changing an [=audio session=]'s [=audio session/state=] to {{AudioSessionState/a * It can [=inactivate=] {{AudioSession}} objects of the [=top-level browsing context=], as defined in the algorithms below. * It can pause the audio of another tab or another application. -Conversely, an [=audio session=] [=audio session/state=] can be modified outside of audio session [=audio session/element=] changes, for instance in case an active [=audio session=] is interrupted. +Conversely, an [=audio session=] [=audio session/state=] can be modified outside of audio session [=audio session/element=] changes, for instance in case an active playback [=audio session=] is interrupted by an incoming phone call. When the user agent observes such a modification, the user agent MUST [=queue a task=] to [=update the state=] of |audioSession|, the {{AudioSession}} object [=tied to=] the modified [=audio session=] with |newState| being the new [=audio session=] [=audio session/state=]. To update the state of |audioSession| with |newState|, the user agent MUST run the following steps: From b521b6878af3d0d0562d1a5239571e1266a8d01a Mon Sep 17 00:00:00 2001 From: Youenn Fablet Date: Mon, 28 Oct 2024 12:35:23 +0100 Subject: [PATCH 4/7] Add transient solo in computation and make ambient the default if there is no active audio session --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 6f758fd..c1901d5 100644 --- a/index.bs +++ b/index.bs @@ -256,9 +256,9 @@ To compute the audio session type of |audioSession|, the user agent M 1. If |audioSession|.[=AudioSession/[[type]]=] is not {{AudioSessionType/auto}}, return |audioSession|.[=AudioSession/[[type]]=]. 1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/play-and-record}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/play-and-record}}. 1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/playback}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/playback}}. +1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/transient-solo}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/transient-solo}}. 1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/transient}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/transient}}. -1. If any |element| of |audioSession|.[=AudioSession/[[elements]]=] has a [=default type=] of {{AudioSessionType/ambient}} and its [=element state|state=] is {{AudioSessionState/active}}, return {{AudioSessionType/ambient}}. -1. Return {{AudioSessionType/auto}}. +1. Return {{AudioSessionType/ambient}}. # Privacy considerations # {#privacy} From aac0e1e074bb238b4c824507fd7e77591f5769ad Mon Sep 17 00:00:00 2001 From: Youenn Fablet Date: Mon, 4 Nov 2024 07:57:54 +0100 Subject: [PATCH 5/7] Taking into account alastor's comments --- index.bs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/index.bs b/index.bs index c1901d5..ab09b69 100644 --- a/index.bs +++ b/index.bs @@ -156,7 +156,7 @@ An [=audio session=] can be in one of the following