diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6289d8bc0f3a633d884cfe099ea90d3575dd1c85..cf65206dbff37ad5cab3314b63bc08cb99a52e37 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,7 +15,7 @@ jobs:
           - "3.7"
           - "3.8"
           - "3.9"
-          # - "3.10"  # FIXME: broken due to `collections.Iterable` issue; see #330 / #624 / etc.
+          - "3.10"
     steps:
       - uses: actions/checkout@v1
       - name: Set up Python ${{ matrix.python-version }}
diff --git a/examples/split_silence.py b/examples/split_silence.py
index a889db101d9ebde254d4e286f3141395b2d9ece5..90b46d95a4966046368518fef135710cfb30128f 100755
--- a/examples/split_silence.py
+++ b/examples/split_silence.py
@@ -27,10 +27,10 @@ parser.add_argument('--start-time', type=float, help='Start time (seconds)')
 parser.add_argument('--end-time', type=float, help='End time (seconds)')
 parser.add_argument('-v', dest='verbose', action='store_true', help='Verbose mode')
 
-silence_start_re = re.compile(' silence_start: (?P<start>[0-9]+(\.?[0-9]*))$')
-silence_end_re = re.compile(' silence_end: (?P<end>[0-9]+(\.?[0-9]*)) ')
+silence_start_re = re.compile(r' silence_start: (?P<start>[0-9]+(\.?[0-9]*))$')
+silence_end_re = re.compile(r' silence_end: (?P<end>[0-9]+(\.?[0-9]*)) ')
 total_duration_re = re.compile(
-    'size=[^ ]+ time=(?P<hours>[0-9]{2}):(?P<minutes>[0-9]{2}):(?P<seconds>[0-9\.]{5}) bitrate=')
+    r'size=[^ ]+ time=(?P<hours>[0-9]{2}):(?P<minutes>[0-9]{2}):(?P<seconds>[0-9\.]{5}) bitrate=')
 
 
 def _logged_popen(cmd_line, *args, **kwargs):
diff --git a/ffmpeg/_run.py b/ffmpeg/_run.py
index 5f25a347b68c3b21b4ee1a46ed11858643b0402d..f42d1d730917075fdd6bb7bfa949eed970139028 100644
--- a/ffmpeg/_run.py
+++ b/ffmpeg/_run.py
@@ -3,7 +3,6 @@ from .dag import get_outgoing_edges, topo_sort
 from ._utils import basestring, convert_kwargs_to_cmd_line_args
 from builtins import str
 from functools import reduce
-import collections
 import copy
 import operator
 import subprocess
@@ -18,6 +17,11 @@ from .nodes import (
     output_operator,
 )
 
+try:
+    from collections.abc import Iterable
+except ImportError:
+    from collections import Iterable
+
 
 class Error(Exception):
     def __init__(self, cmd, stdout, stderr):
@@ -136,9 +140,7 @@ def _get_output_args(node, stream_name_map):
         args += ['-b:a', str(kwargs.pop('audio_bitrate'))]
     if 'video_size' in kwargs:
         video_size = kwargs.pop('video_size')
-        if not isinstance(video_size, basestring) and isinstance(
-            video_size, collections.Iterable
-        ):
+        if not isinstance(video_size, basestring) and isinstance(video_size, Iterable):
             video_size = '{}x{}'.format(video_size[0], video_size[1])
         args += ['-video_size', video_size]
     args += convert_kwargs_to_cmd_line_args(kwargs)
diff --git a/ffmpeg/_utils.py b/ffmpeg/_utils.py
index 94ef9d070cfc0431d6007264a466f492ecdba1ff..9baa2c78ce17b8698e38a0008346e31ce2a327c3 100644
--- a/ffmpeg/_utils.py
+++ b/ffmpeg/_utils.py
@@ -3,13 +3,17 @@ from builtins import str
 from past.builtins import basestring
 import hashlib
 import sys
-import collections
 
 
 if sys.version_info.major == 2:
     # noinspection PyUnresolvedReferences,PyShadowingBuiltins
     str = str
 
+try:
+    from collections.abc import Iterable
+except ImportError:
+    from collections import Iterable
+
 
 # `past.builtins.basestring` module can't be imported on Python3 in some environments (Ubuntu).
 # This code is copy-pasted from it to avoid crashes.
@@ -92,7 +96,7 @@ def convert_kwargs_to_cmd_line_args(kwargs):
     args = []
     for k in sorted(kwargs.keys()):
         v = kwargs[k]
-        if isinstance(v, collections.Iterable) and not isinstance(v, str):
+        if isinstance(v, Iterable) and not isinstance(v, str):
             for value in v:
                 args.append('-{}'.format(k))
                 if value is not None:
diff --git a/ffmpeg/tests/test_ffmpeg.py b/ffmpeg/tests/test_ffmpeg.py
index ba1fa3612ca071c7b0f9cae084f50c9a0ff019c6..8dbc271a79a8946c2c3f254f0e47e0a817930634 100644
--- a/ffmpeg/tests/test_ffmpeg.py
+++ b/ffmpeg/tests/test_ffmpeg.py
@@ -30,7 +30,7 @@ subprocess.check_call(['ffmpeg', '-version'])
 
 
 def test_escape_chars():
-    assert ffmpeg._utils.escape_chars('a:b', ':') == 'a\:b'
+    assert ffmpeg._utils.escape_chars('a:b', ':') == r'a\:b'
     assert ffmpeg._utils.escape_chars('a\\:b', ':\\') == 'a\\\\\\:b'
     assert (
         ffmpeg._utils.escape_chars('a:b,c[d]e%{}f\'g\'h\\i', '\\\':,[]%')
diff --git a/setup.py b/setup.py
index 743deb22ab06766cddb61d04b62101d1b09d9760..72f381cb5339df8421a282e3c3439b67bcf7c04f 100644
--- a/setup.py
+++ b/setup.py
@@ -92,5 +92,9 @@ setup(
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7',
+        'Programming Language :: Python :: 3.8',
+        'Programming Language :: Python :: 3.9',
+        'Programming Language :: Python :: 3.10',
     ],
 )
diff --git a/tox.ini b/tox.ini
index e317207f4719ec2a42a5dc7c498e8010dcfe3bd1..98814078432d7995e30a2209123f7bac83e4dfec 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,7 +4,7 @@
 # and then run "tox" from this directory.
 
 [tox]
-envlist = py27, py35, py36, py37, py38, py39
+envlist = py27, py35, py36, py37, py38, py39, py310
 
 [gh-actions]
 python =
@@ -14,6 +14,7 @@ python =
     3.7: py37
     3.8: py38
     3.9: py39
+    3.10: py310
 
 [testenv]
 commands = py.test -vv