+1 vote

Hey, I'm trying to make a game with an online radio station tuner, but every time I update the stream data with a fresh chunk the playback stops. Therefore, I'm forced to play(). This results in very choppy audio.

If using large buffers for the stream, it will hiccup less frequently, but this will result in a long initial buffer time. This is still not ideal. I have tried to union stream.data with mp3_stream.data, but playback stops. No matter how I try to edit AudioStreamMP3's data, it will always stop the playback.

I have tried masking the hiccup with static and it sounds janky as heck.

I'm hoping there is way to mitigate this issue. It's driving me nuts. Do you think it's worth creating a second AudioStreamPlayer to switch between the two? I'd imagine it'd be difficult to sync these up.

Thanks!

extends AudioStreamPlayer

export(String) var station_name
export(String) var station_endpoint_url = "74.208.71.58"
export(int, 0, 65535) var station_endpoint_port = 8087
export(int, 0, 256) var buffer_kb = 64
export(float, 0, 1, 0.01) var frequency = .5
export(float, 87.9, 107.9, 0.1) var channel = 97.9
export(float, .05, .15) var bandwidth = .1
export(float, 0, 1) var signal_strength = 1
export(String, MULTILINE) var http_request = "GET / HTTP/1.1\n\n"
var mp3_stream = AudioStreamMP3.new()

var streaming = true
var stream_peer = StreamPeerTCP.new()

func _ready():
    http_request = http_request.to_utf8()
    stream_peer.connect_to_host(station_endpoint_url, station_endpoint_port)

func _physics_process(delta):
    if streaming:
        stream_peer.put_data(http_request)
        if stream_peer.get_status() == stream_peer.STATUS_CONNECTED:
            var available_bytes = stream_peer.get_available_bytes()

            # When payload is ready, update the stream
            if available_bytes >= buffer_kb * 1000:
                mp3_stream.data = stream_peer.get_data(available_bytes)[1]
                print("*hiccup*")
                stream = mp3_stream
                play()
Godot version v3.3.2
in Engine by (13 points)
edited by

Thanks for sharing. I have added some probing + main scene

Probing


signal data_available(d)

func _process(delta):
    if stream != null:
        emit_signal("data_available", {
            'position' : get_playback_position(),
            'available': stream_peer.get_available_bytes(),
            'stream': stream.get_length()
        })

...
            printt("*hiccup*", get_playback_position())
...

Main


extends Control onready var button:Button = $Button
onready var station = $AudioStreamPlayer
onready var label:Label = $Label func ready():
button.connect("button
up", self, 'play')
station.connect("dataavailable", self, 'dataavailable') func play():
station.play() func data_available(d:Dictionary):
label.text = String(d.position) + '\n' + String(d.available) + '\n' + String(d.stream)

You are requesting data every physics FPS (60/120?) which seems a lot to me.

The hickup itself is caused by overriding a playing stream not yet ended. Is that fixable?

The app disfunction after a while too.

E 0:06:12.942 getavailablebytes: Condition "!isopen()" is true. Returned: -1
<C++ Source> drivers/unix/net
socketposix.cpp:705 @ getavailable_bytes()
AudioStreamPlayer.gd:28 @ _process()

Error is because connection was closed.

Regarding number of request:

First data gets on request number 16!

16 Bytes available 454
17 Bytes available 4678
24 Bytes available 6086
25 Bytes available 14534
32 Bytes available 17350
33 Bytes available 34246
40 Bytes available 39878
41 Bytes available 63814
48 Bytes available 66126

To fix this only 'open' the request once


var has_connection:bool = false
...
            if not has_connection:
                stream_peer.put_data(http_request)
                has_connection = true
...

There are other stream types like AudioStreamGeneratorPlayback which got discussed in https://github.com/godotengine/godot/issues/46490 ... in the end they suggest to use a Thread (for VOIP) but I guess for this we only need to append to the buffer.

Maybe this https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator helps.

Please let me/us know your solutions :-)

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.