Empty WAV file is created when recording a call
When using the Record() function (based on the diago example), an empty WAV file is created at the specified path, but no audio data is written to it.
Code Snippet: The issue occurs after successfully creating a dialog session:
dialog, err := tu.Invite(ctx, client, diago.InviteOptions{
Username: regOpts.Username,
Password: regOpts.Password
})
Recording function implementation:
func Record(outDialog *diago.DialogClientSession) error {
// Create wav file to store recording
wawFile, err := os.OpenFile("D:\\data\\"+outDialog.InviteRequest.CallID().Value()+".wav", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
return err
}
defer wawFile.Close()
// Create recording audio pipeline
rec, err := outDialog.AudioStereoRecordingCreate(wawFile)
if err != nil {
return err
}
// Must be closed for correct flushing
defer func() {
if err := rec.Close(); err != nil {
slog.Error("Failed to close recording", "error", err)
}
}()
// Do echo with audio reader and writer from recording object
_, err = media.Copy(rec.AudioReader(), rec.AudioWriter())
if errors.Is(err, io.EOF) {
// Call finished
return nil
}
return err
}
Actual Behavior:
A WAV file is created at the specified path, but it remains empty just with format header like RIFF$ WAVEfmt @ } data .
Additional Context:
Followed the example from: https://github.com/emiago/diago/blob/main/examples/wav_record/main.go
No errors are returned during the recording process
The file permissions seem correct (can create/write to the location)
The call itself establishes successfully, just no audio is recorded
Hi @Malfarion . Thanks for opening. Must be some small issue if above is true. I will recheck example, although this is integrated to gophone https://github.com/emiago/gophone
Seems all fine. I have now added to dump file location where this is stored. please recheck and reopen if needed.
Hi @emiago. I'm still having an issue with client-side recording.
For context:
- I'm testing from a Windows environment
- Not using server-side recording
- Can provide full logs/repro steps if needed
Could you also please change both instances in https://github.com/emiago/diago/blob/03ba39b9b8f8189f7ef13f1ed4b1368935a837ee/audio/monitor_pcm.go#L160 from the hardcoded /tmp/ to os.TempDir()?
PS: I already did it locally, so it's not the reason for the empty WAV.
@Malfarion do you still have the issue? i got the same one.
@emiago @tarcanscloud Yes, and unfortunately i have no option to reopen issue, button is grey.
hi @Malfarion . Yes that should be fixed. I will add commit for that. Do you think that could be issue? It is interesting that this fails on windows.
I used the example code from https://github.com/emiago/diago/blob/main/examples/wav_record/main.go and added a registration step. It answers the call fine, but the recording file ends up empty (actually 44 bytes, but it won’t play).
This is recorded file content.
The code:
package main
import (
"context"
"errors"
"fmt"
"io"
"log/slog"
"os"
"os/signal"
"github.com/emiago/diago"
"github.com/emiago/diago/examples"
"github.com/emiago/diago/media"
"github.com/emiago/sipgo"
"github.com/emiago/sipgo/sip"
)
const (
user = "TODO"
password = "TODO"
host = "TODO"
port = 5060
)
// Dial this app with
// gophone dial -media=audio "sip:[email protected]"
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
examples.SetupLogger()
err := start(ctx)
if err != nil {
slog.Error("PBX finished with error", "error", err)
}
}
func start(ctx context.Context) error {
// Setup our main transaction user
ua, _ := sipgo.NewUA()
tu := diago.NewDiago(ua)
go func() {
uri := sip.Uri{}
sip.ParseUri(
fmt.Sprintf(
"sip:%s@%s:%d",
user,
host,
port,
),
&uri,
)
slog.Info("registering", slog.String("uri", uri.String()))
err := tu.Register(
ctx,
uri,
diago.RegisterOptions{
Username: user,
Password: password,
},
)
if err != nil {
panic(err)
}
}()
return tu.Serve(ctx, func(inDialog *diago.DialogServerSession) {
slog.Info("New dialog request", "id", inDialog.ID)
defer slog.Info("Dialog finished", "id", inDialog.ID)
if err := Record(inDialog); err != nil {
slog.Error("Record finished with error", "error", err)
}
})
}
func Record(inDialog *diago.DialogServerSession) error {
inDialog.Trying() // Progress -> 100 Trying
inDialog.Ringing() // Ringing -> 180 Response
if err := inDialog.Answer(); err != nil {
return err
} // Answer -> 200 Response
// Create wav file to store recording
filename := "/tmp/diago_record_" + inDialog.InviteRequest.CallID().Value() + ".wav"
slog.Info("Creating new recording", "filename", filename)
wawFile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
return err
}
defer wawFile.Close()
// Create recording audio pipeline
rec, err := inDialog.AudioStereoRecordingCreate(wawFile)
if err != nil {
return err
}
// Must be closed for correct flushing
defer func() {
if err := rec.Close(); err != nil {
slog.Error("Failed to close recording", "error", err)
}
}()
// Do echo with audio reader and writer from recording object
_, err = media.Copy(rec.AudioReader(), rec.AudioWriter())
if errors.Is(err, io.EOF) {
// Call finished
return nil
}
return err
}
is it the same issue as your? @Malfarion
Thanks @emiago for reopen the issue 🥹
FYI. Recording is only full if streaming is working. Can you actually create PCAP of your calls?
@emiago I think that's the point. I can't see any incoming RTP packet. Can you? Not sure if it only happened on my machine.
@tarcanscloud I think than this is different issue. Sorry but I have no idea what are you doing. Recording I have no issues, but I could see some Windoes problems which should be resolved on main branch.