From a5726ae865d61af1ebe43d4e1f8b75c1dfb08159 Mon Sep 17 00:00:00 2001
From: David Zhao <dz@livekit.io>
Date: Wed, 4 Dec 2024 02:37:27 -0600
Subject: [PATCH] Support mute/unmute for local tracks (#318)

---
 examples/room_example.py         | 13 ++++++++-----
 livekit-rtc/livekit/rtc/track.py | 28 ++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/examples/room_example.py b/examples/room_example.py
index 6e01e89c..f71ca963 100644
--- a/examples/room_example.py
+++ b/examples/room_example.py
@@ -10,11 +10,12 @@
 
 async def main():
     logging.basicConfig(level=logging.INFO)
+    logger = logging.getLogger(__name__)
     room = rtc.Room()
 
     @room.on("participant_connected")
     def on_participant_connected(participant: rtc.RemoteParticipant):
-        logging.info(
+        logger.info(
             "participant connected: %s %s", participant.sid, participant.identity
         )
 
@@ -30,7 +31,7 @@ def on_track_subscribed(
         publication: rtc.RemoteTrackPublication,
         participant: rtc.RemoteParticipant,
     ):
-        logging.info("track subscribed: %s", publication.sid)
+        logger.info("track subscribed: %s", publication.sid)
         if track.kind == rtc.TrackKind.KIND_VIDEO:
             video_stream = rtc.VideoStream(track)
             asyncio.ensure_future(receive_frames(video_stream))
@@ -38,7 +39,7 @@ def on_track_subscribed(
     # By default, autosubscribe is enabled. The participant will be subscribed to
     # all published tracks in the room
     await room.connect(URL, TOKEN)
-    logging.info("connected to room %s", room.name)
+    logger.info("connected to room %s", room.name)
 
     for identity, participant in room.remote_participants.items():
         print(f"identity: {identity}")
@@ -48,8 +49,10 @@ def on_track_subscribed(
         print(f"participant identity: {participant.identity}")
         print(f"participant name: {participant.name}")
         print(f"participant kind: {participant.kind}")
-        print(f"participant track publications: {
-              participant.track_publications}")
+        print(
+            f"participant track publications: {
+              participant.track_publications}"
+        )
         for tid, publication in participant.track_publications.items():
             print(f"\ttrack id: {tid}")
             print(f"\t\ttrack publication: {publication}")
diff --git a/livekit-rtc/livekit/rtc/track.py b/livekit-rtc/livekit/rtc/track.py
index de870481..8a6fe692 100644
--- a/livekit-rtc/livekit/rtc/track.py
+++ b/livekit-rtc/livekit/rtc/track.py
@@ -80,6 +80,20 @@ def create_audio_track(name: str, source: "AudioSource") -> "LocalAudioTrack":
         resp = FfiClient.instance.request(req)
         return LocalAudioTrack(resp.create_audio_track.track)
 
+    def mute(self):
+        req = proto_ffi.FfiRequest()
+        req.local_track_mute.track_handle = self._ffi_handle.handle
+        req.local_track_mute.mute = True
+        FfiClient.instance.request(req)
+        self._info.muted = True
+
+    def unmute(self):
+        req = proto_ffi.FfiRequest()
+        req.local_track_mute.track_handle = self._ffi_handle.handle
+        req.local_track_mute.mute = False
+        FfiClient.instance.request(req)
+        self._info.muted = False
+
     def __repr__(self) -> str:
         return f"rtc.LocalAudioTrack(sid={self.sid}, name={self.name})"
 
@@ -97,6 +111,20 @@ def create_video_track(name: str, source: "VideoSource") -> "LocalVideoTrack":
         resp = FfiClient.instance.request(req)
         return LocalVideoTrack(resp.create_video_track.track)
 
+    def mute(self):
+        req = proto_ffi.FfiRequest()
+        req.local_track_mute.track_handle = self._ffi_handle.handle
+        req.local_track_mute.mute = True
+        FfiClient.instance.request(req)
+        self._info.muted = True
+
+    def unmute(self):
+        req = proto_ffi.FfiRequest()
+        req.local_track_mute.track_handle = self._ffi_handle.handle
+        req.local_track_mute.mute = False
+        FfiClient.instance.request(req)
+        self._info.muted = False
+
     def __repr__(self) -> str:
         return f"rtc.LocalVideoTrack(sid={self.sid}, name={self.name})"