rind: Begin audio code

I don't yet have UI widgets, but this should cover the basics of audio
playback.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
This commit is contained in:
Anna Schumaker 2019-03-18 17:18:59 -04:00
parent e9e056e925
commit b42c654c2c
2 changed files with 145 additions and 0 deletions

55
rind/gst.py Normal file
View File

@ -0,0 +1,55 @@
# Copyright 2019 (c) Anna Schumaker.
import curds
import gi
import sys
gi.require_version("Gst", "1.0")
from gi.repository import Gst, GLib
class EmmentalAudio:
def __init__(self):
self.playbin = Gst.ElementFactory.make("playbin")
self.bus = self.playbin.get_bus()
self.bus.add_signal_watch()
self.bus.connect("message", self.on_message)
def duration(self):
(res, cur) = self.playbin.query_duration(Gst.Format.TIME)
return cur / Gst.SECOND if res == True else 0.0
def load(self, track, play=True):
if track:
self.playbin.set_property("uri", f"file://{track.path}")
self.playbin.set_state(Gst.State.PLAYING if play else Gst.State.PAUSED)
def next(self):
track = curds.PlaylistManager.next()
if track != None:
self.load(track)
def on_message(self, bus, message):
if message.type == Gst.MessageType.STATE_CHANGED:
(old, new, pending) = message.parse_state_changed()
curds.Notify.notify("state-changed", new)
elif message.type == Gst.MessageType.STREAM_START:
curds.Notify.notify("duration-changed", self.duration())
return True
def pause(self):
self.playbin.set_state(Gst.State.PAUSED)
def play(self):
self.playbin.set_state(Gst.State.PLAYING)
def position(self):
(res, cur) = self.playbin.query_position(Gst.Format.TIME)
return cur if res == True else 0
def progress(self):
pos = self.position()
dur = self.duration()
return (pos / dur) if dur > 0 else 0
def state(self):
return self.playbin.get_state(Gst.CLOCK_TIME_NONE)[1]
Gst.init(sys.argv)

90
rind/test_gst.py Normal file
View File

@ -0,0 +1,90 @@
# Copyright 2019 (c) Anna Schumaker.
from . import gst
import curds
import os
import time
import unittest
from gi.repository import Gst, GLib
test_album = os.path.abspath("./trier/Test Library/Test Artist 01/Test Album 1")
class TestGst(unittest.TestCase):
def setUp(self):
self.state = None
self.duration = None
curds.PlaylistManager["Collection"].list.clear()
curds.PlaylistManager["Library"].clear()
curds.Notify.notify_me("new-track", curds.PlaylistManager["Collection"].add)
if not curds.playlist.library.library_thread.is_alive():
curds.playlist.library.library_thread = curds.ThreadQueue()
curds.Notify.notify_me("state-changed", self.on_state_changed)
curds.Notify.notify_me("duration-changed", self.on_duration_changed)
def tearDown(self):
curds.playlist.library.library_thread.stop()
def main_loop(self):
events = GLib.main_context_default().iteration()
while events == True:
events = GLib.main_context_default().iteration(may_block=False)
def test_gst_init(self):
audio = gst.EmmentalAudio()
self.assertIsInstance(audio.playbin, Gst.Element)
self.assertIsInstance(audio.bus, Gst.Bus)
self.assertEqual(audio.state(), Gst.State.NULL)
audio.load(None)
self.assertEqual(audio.state(), Gst.State.NULL)
audio.play()
self.assertEqual(audio.state(), Gst.State.READY)
audio.pause()
self.assertEqual(audio.state(), Gst.State.READY)
self.assertEqual(audio.position(), 0)
self.assertEqual(audio.duration(), 0)
self.assertEqual(audio.progress(), 0)
def on_state_changed(self, state):
self.state = state
def on_duration_changed(self, duration):
self.duration = duration
def test_gst_load(self):
audio = gst.EmmentalAudio()
track = curds.Track.lookup(os.path.join(test_album, "10 - Test Track 10.ogg"))
self.main_loop()
self.state = None
self.duration = None
audio.load(track)
while self.state == None or self.duration == None:
self.main_loop()
self.assertEqual(self.state, Gst.State.PAUSED)
self.assertEqual(audio.position(), 0)
self.assertEqual(audio.duration(), 10.0)
self.assertEqual(audio.progress(), 0)
while self.state != Gst.State.PLAYING:
self.main_loop()
def test_gst_controls(self):
audio = gst.EmmentalAudio()
self.assertEqual(audio.state(), Gst.State.NULL)
audio.next()
self.assertEqual(audio.state(), Gst.State.NULL)
self.assertIsNone(curds.PlaylistManager.track)
curds.PlaylistManager["Library"].add(test_album)
curds.playlist.library.library_thread.join()
self.state == None
audio.next()
self.assertIsNotNone(curds.PlaylistManager.track)
while self.state != Gst.State.PLAYING:
self.main_loop()
audio.pause()
while self.state != Gst.State.PAUSED:
self.main_loop()