Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streaming Media Manager 5.0 #56

148 changes: 148 additions & 0 deletions proposals/nnnn-streaming-media-manager-update.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Streaming Media Manager 5.0
* Proposal: [SDL-NNNN](NNNN-filename.md)
* Author: [Alex Muller](https://github.com/asm09fsu)
* Status: **Awaiting review**
* Impacted Platforms: iOS / Protocol

## Introduction
This proposal is geared at revamping how the Streaming Media Manager (SMM) class manages audio/video streaming. This revamp will also include lifecycle management for these streams as the overall app/proxy lifecycle changes.


## Motivation
We currently have a SMM which provides the basic functionality for streaming audio and video, however much of the management of this class is still up to the developer, and may vary by implementations. In order to allow developers to deliver high quality mobile navigation experiences, the SMM should be revamped to remove much of the bloat and management of the sessions internally and allow the developers to easily use this class for mobile navigation applications. If you need a real reason for why this should be considered, look at the Detailed Design section for all the possible complexities we expect every developer to implement.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need a real reason for why this should be considered, look at the Detailed Design section for all the possible complexities we expect every developer to implement.

Are you currently giving me the fake reason? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes



## Proposed solution
#### Current Supported Features:
- Starting/Stopping video session with different encryption flags
- Starting/Stopping audio session with different encryption flags
- Sending video data via `CVImageBufferRef`
- Sending audio data via `NSData` of PCM data
- Ability to interact with `SDLTouchManager`
- Ability to set custom video encoder settings
- Access to the shared `CVPixelBufferPoolRef` provided by the encoder
- Access to the screen size of the connected head unit.

#### New Features
- Management of the video session lifecycle in conjunction with proxy & app state changes
- Management of the audio session lifecycle in conjunction with proxy & app state changes
- Ability to register to a touch manager handler for touch events.

## Detailed design
There are multiple parts of the proxy lifecycle that the SMM would have an impact on.
#### `SDLLifecycleManager`
If the application has an `SDLLifecycleConfiguration` with the `appType` of `NAVIGATION`, then SMM will be started automatically once `SDLLifecycleManager` enters the state `didEnterStateSettingUpManagers`. This would simply start the manager, not the sessions. At this point, SMM is ready and listening to HMI status changes and will internally start/stop protocols.
#### `SDLStreamingMediaManager`
Due to the need to make sure we properly unit test all possible combinations of HMI, app and streaming states, we need to be able to change the state machine at will. This, however, should not be exposed to the developer. Because of this, `SDLStreamingMediaManager` will be a wrapper around `SDLStreamingMediaLifecycleManager`, similar to how `SDLManager` is a wrapper around `SDLLifecycleManager`.

#### `SDLStreamingMediaLifecycleManager`
##### State Machines
There will need to be multiple state machines that need to work together to deal with all the possible scenarios the app can be in on both the phone and head unit. Luckily, HMI states are already provided so we will not be building a new state machine, but will list the possible scenarios for different states below.
###### Phone (new state machine)
1. Resigning Active
- The app is moving to the background. If the streaming state is **Ready**, and in HMI **Limited or greater**, we should send ~30 frames so that we can alert the user to reopen the app. The streams will remain open. Can move to **Backgrounded**.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 30 frames?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

30 frames guarantees that we send enough to be visible on the head unit. This can be changed, but in testing this seems to be a good amount.

2. Backgrounded
- The app is currently in the background, and cannot use the encoder to send over frames. Regardless of HMI changes, we cannot stream video. The stream should remain open if currently open. If the HMI changes to **Background or less**, we should close the sessions, and the Streaming state will move to **Stopped**. Can move to **Regaining Active**.
3. Regaining Active
- The app is currently regaining it’s position as the foreground app. If we are currently in HMI **Limited or greater**, and the Streaming state is **Ready**, we will restart the streams by moving to state **Stopped**, and then **Starting**, followed by **Ready**. Can move to **Active**.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this just be that the streaming state machine would just move to starting? It should already be in stopped, and ready is conditional on the streaming state machine, not this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, as we must stop and restart the sessions by sending an end session and then a start session.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then why does 2. Backgrounded say it's moved to stopped? Is it moving from stopped to stopped again?

Copy link
Contributor Author

@asm09fsu asm09fsu Mar 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The streaming state is independent from the app and hmi state. The streaming state moves to stopped only if the HMI state goes to background or none. In all other instances, the stream stays open. Not sure where you are getting stopped -> stopped?

4. Active
- The app is in the foreground. We are able to stream if needed, permitting we are in the proper HMI. Can move to **Resigning Active**.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

permitting

"assuming"?


###### HMI (states already available)
1. None
* App has not been opened yet, or was closed via the app’s Menu button. If the streaming session is **Ready**, we need to move to **Stopped**.
2. Background
- App was open, however a new streaming app has been opened, and is taking streaming priority. If the streaming session is **Ready**, we need to move to **Stopped**.
3. Limited
- App was open, however the user has moved to another screen on the head unit. This app is still the primary streaming app. The Streaming State must not move from **Ready**, however if the Phone State is moving from **Active** to **Resigning Active**, we must send 30 frames.
4. Full
- App is open, and is currently in focus. If the Streaming State is currently **Stopped**, we should proceed to **Starting**, so long as the Phone State is not **Resigning Active** or **Backgrounded**. If moving to this state and the Phone State is currently **Regaining Active** or **Active**, and the Streaming State is currently **Ready**, the Streaming State should be moved to **Stopped** followed by **Starting** (restarting the streams). If moving to this state and the Phone State is currently **Backgrounded**, send an RPC to alert the user to open the app (current suggestion is an Alert with TTS).

###### Streaming (new state machine)
1. Stopped
- Streaming is stopped, and sessions are closed. Can move to **Starting** only if HMI is **Limited or greater** and Phone State is **Regaining Active** or **Active**.
2. Starting
- Streaming sessions are being opened, and encoder is being prepared. Can move to **Ready** only if HMI is **Limited or greater** and Phone State is **Regaining Active** or **Active**. If not, move to **Stopped**.
3. Ready
- Streaming sessions and encoder are ready. This state is only active so long as HMI is **Limited or greater** and Phone State is **Regaining Active** or **Active**. If at this state, and Phone State changes to **Resigning Active**, send ~30 frames. If at this state, and HMI changes to **Background or less**, move to **Stopped**.

###### Video Lifecycle Chart
HMI State | App State | Can Open Video Stream | Should Close Video Stream
------------|-------------------|-----------------------|--------------------------
NONE | Background | No | Yes
NONE | Regaining Active | No | Yes
NONE | Foreground | No | Yes
NONE | Resigning Active | No | Yes
BACKGROUND | Background | No | Yes
BACKGROUND | Regaining Active | No | Yes
BACKGROUND | Foreground | No | Yes
BACKGROUND | Resigning Active | No | Yes
LIMITED | Background | No | No
LIMITED | Regaining Active | Yes | Yes
LIMITED | Foreground | Yes | No
LIMITED | Resigning Active | No | No
FULL | Background | No | No
FULL | Regaining Active | Yes | Yes
FULL | Foreground | Yes | No
FULL | Resigning Active | No | No

###### Audio Stream Lifecycle Chart
Since the app state is irrelevant for audio streaming (because we can do this in the background), the lifecycle chart is a bit simpler than the video lifecycle chart.

HMI State | Can Open Audio Stream | Should Close Audio Stream
------------|-----------------------|--------------------------
NONE | No | Yes
BACKGROUND | No | Yes
LIMITED | Yes | No
FULL | Yes | No

##### Sending Video Data
The way in which video frames are sent over will not change from the current implementation. This function will require input of a `CVImageBufferRef` for video. It will be up to the developer to decide how to frequently to call this function. The developer will be able to know if the currently connected stream is encrypted with a `BOOL` `isEncrypted`, a `CGSize` `screenSize` to let them know the current Head Unit screen size, and a `CVPixelBufferPoolRef` for using the encoder’s pixel buffer pool, as is currently available in SMM.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume isEncrypted et. al. are actually encrypted with the getter prepending the is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

There will also be getter `isVideoStreamingPaused` that informs a developer to if sending of video data is not occurring based on circumstances where there’s not a need to send frames. If video streaming moves to a state where streaming cannot occur (i.e. HMI state changes to Limited, or Phone state move to Resigning Active), `isVideoStreamingPaused` will be set to `YES`, and will resume when possible.

The thought for implementation is as follows:
```objc
// Checking if SMM is paused
if (streamingMediaManager.isVideoStreamingPaused) {
<#pause pulling of frames if running#>
return;
}

// Sending Video Data
CVPixelBufferPoolRef pixelBufferPool = streamingMediaManager.pixelBufferPool;
CGSize screenSize = streamingMediaManager.screenSize;

CVImageBufferRef frame = <#acquire video frame#>
[streamingMediaManager sendVideoFrame:frame];
```

##### Sending video data when iPhone is moving to background
Since iOS cannot use the encoder when the phone is in the background, to conserve battery and CPU, we must find a solution that will drive the user to reopen the app. The suggested solution is to create a single frame that is generated when SMM’s encoder is initialized, and send that over as the Phone State changes from **Active** to **Resigning Active**. This should be built as a non-customizable screen, so that we can rely on consistent behavior among streaming applications for the time being. The current idea is to have a black screen with the text “Please re-open <#App Name#>”. We have the option to provide translations for all languages that SDL supports, if we wish to go that route. We can also use the app icon, if we wish instead of the app name, as the app name could potentially be quite long.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not 100% clear, but it looks like you're saying this would be built into the SMM?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say both name and icon could be helpful. Do we have an idea for how this might be implemented?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be implemented in SMM, but that's the point of the proposal is to see if that is ideal. We could do an XIB, or dynamically generate an image. Just depends on if we want to give the developers to ability to customize. The only problem with customization is we must make sure it is NHTSA compliant for US market.


##### Sending Audio Data
Since audio data is sent sporadically, we will have a function that will send audio data only when necessary.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this already exist? I'm confused if this is a comprehensive overview or just showing the changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an entire rewrite of SMM, so this will contain an overview.

```objc
// Sending Audio Data
[streamingMediaManager sendAudioData:<#audioData#>];
```

#### `SDLTouchManager`
Currently, the `SDLTouchManager` class allows for developers to use a provided set of callbacks so they do not have to provide logic for determining gesture events such as tap, double tap, pinch, and pan. There are some developers, however, that would still like the ability to use their own. Currently, developers can listen to `SDLOnTouchEvent` notifications, and consume the object themselves, however a proposed solution is to make the internal `SDLTouch` object public, and allow for developers to use a handler on `SDLTouchManager` that will provide this touch object back, along with the `SDLTouchType`, to make it easier to handle and consume `SDLOnTouchEvent`.

We would add a property to `SDLTouchManager` called `touchEventHandler`:
```objc
typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);

/**
* @abstract
* Returns all OnTouchEvent notifications as SDLTouch and SDLTouchType objects.
*/
@property (copy, nonatomic, nullable) SDLTouchEventHandler touchEventHandler;

```

## Impact on existing code
The impact on SDL is that the previous version of `SDLStreamingMediaManager` and all code associated will no longer work. This will require a developer to adapt to using this new method of streaming, but will greatly improve the efficiency of Mobile Navigation Apps.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems mostly additive, public API-wise. What behavior prevents current code from working with this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not only additive. We are completely removing the ability to start/stop the sessions, because we want consistent lifecycle between all streaming apps.


## Alternatives considered
The alternative decision of keeping the SMM as is was considered, but it is thought as not ideal because this forces the developer to implement the logic for different states of the application both on device, and also on the head unit. This should be consistent across all apps so we can make sure the experience is ideal and consistent for all users.