Repository: gradio-app/gradio

Issue:
Stop event handler not triggered for audio
### Describe the bug

The `stop` event handle is not triggered for audio

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Reproduction

```
import gradio as gr

def stop_streaming():
    print("Streaming has stopped")

if __name__ == "__main__":

    with gr.Blocks() as demo:

        stream_input = gr.Audio(source="microphone")
        stream_input.stop(stop_streaming)

    demo.queue().launch(share=False,  debug=False)
```

### Screenshot

"Streaming has stopped" is not printed to the console.

![image](https://user-images.githubusercontent.com/41651716/235471015-e9f03d52-0187-4c14-a768-35480545550a.png)


### Logs

```shell
-
```


### System Info

```shell
3.28.1
```


### Severity

serious, but I can work around it


Discussion:
Should check all the `Playable` events (stop, pause, play) work as well!
I don't think we have ever emitted a `stop` event when the webcam recording is stopped. I think those events are only triggered by the player. 

We may want to consider separate events for start and stop recording because they are different to simply stopping an existing media track. 
I checked and we haven't, this is a feature request (although a sensible one). 
What's the difference between `stop` and `pause` events (both defined on Playable event class)? 
I'm using a very inefficient method to catch stops, is there any chance this could be improved?
> I'm using a very inefficient method to catch stops, is there any chance this could be improved?

@caffeinism Could you share the code sample for how you have the workaround to catch stops? Thanks!

Resolving patch:
diff --git a/gradio/components.py b/gradio/components.py
--- a/gradio/components.py
+++ b/gradio/components.py
@@ -64,6 +64,7 @@
     EventListenerMethod,
     Inputable,
     Playable,
+    Recordable,
     Releaseable,
     Selectable,
     Streamable,
@@ -2134,6 +2135,7 @@ class Video(
     Changeable,
     Clearable,
     Playable,
+    Recordable,
     Uploadable,
     IOComponent,
     VideoSerializable,
@@ -2482,6 +2484,7 @@ class Audio(
     Changeable,
     Clearable,
     Playable,
+    Recordable,
     Streamable,
     Uploadable,
     IOComponent,
diff --git a/gradio/events.py b/gradio/events.py
--- a/gradio/events.py
+++ b/gradio/events.py
@@ -131,6 +131,11 @@ def __call__(
             warnings.warn(
                 "The 'status_tracker' parameter has been deprecated and has no effect."
             )
+        if self.event_name == "stop":
+            warnings.warn(
+                "The `stop` event on Video and Audio has been deprecated and will be remove in a future version. Use `ended` instead."
+            )
+
         if isinstance(self, Streamable):
             self.check_streamable()
         if isinstance(show_progress, bool):
@@ -234,13 +239,19 @@ def __init__(self):
 
         self.pause = EventListenerMethod(self, "pause")
         """
-        This listener is triggered when the user pauses the component (e.g. audio or video).
+        This listener is triggered when the media stops playing for any reason (e.g. audio or video).
         This method can be used when this component is in a Gradio Blocks.
         """
 
         self.stop = EventListenerMethod(self, "stop")
         """
-        This listener is triggered when the user stops the component (e.g. audio or video).
+        This listener is triggered when the user reaches the end of the media track (e.g. audio or video).
+        This method can be used when this component is in a Gradio Blocks.
+        """
+
+        self.end = EventListenerMethod(self, "end")
+        """
+        This listener is triggered when the user reaches the end of the media track (e.g. audio or video).
         This method can be used when this component is in a Gradio Blocks.
         """
 
@@ -264,6 +275,22 @@ def check_streamable(self):
         pass
 
 
+@document("*start_recording", "*stop_recording", inherit=True)
+class Recordable(EventListener):
+    def __init__(self):
+        self.start_recording = EventListenerMethod(self, "start_recording")
+        """
+        This listener is triggered when the user starts recording with the component (e.g. audio or video).
+        This method can be used when this component is in a Gradio Blocks.
+        """
+
+        self.stop_recording = EventListenerMethod(self, "stop_recording")
+        """
+        This listener is triggered when the user stops recording with the component (e.g. audio or video).
+        This method can be used when this component is in a Gradio Blocks.
+        """
+
+
 @document("*blur", inherit=True)
 class Blurrable(EventListener):
     def __init__(self):


Test patch: