<commit_before>package gumble_ffmpeg

import (
	"encoding/binary"
	"errors"
	"io"
	"os/exec"
	"strconv"
	"time"

	"github.com/layeh/gumble/gumble"
)

var (
	ErrState = errors.New("invalid state")
)

type Stream struct {
	client     *gumble.Client
	cmd        *exec.Cmd
	pipe       io.ReadCloser
	sourceStop chan bool
}

func New(client *gumble.Client) (*Stream, error) {
	stream := &Stream{
		client: client,
	}
	return stream, nil
}

func (s *Stream) Play(file string) error {
	if s.sourceStop != nil {
		return ErrState
	}
	s.cmd = exec.Command("ffmpeg", "-i", file, "-ac", "1", "-ar", strconv.Itoa(gumble.AudioSampleRate), "-f", "s16le", "-")
	if pipe, err := s.cmd.StdoutPipe(); err != nil {
		s.cmd = nil
		return nil
	} else {
		s.pipe = pipe
	}
	s.sourceStop = make(chan bool)
	go s.sourceRoutine()
	s.cmd.Start()
	return nil
}

func (s *Stream) Stop() error {
	if s.sourceStop != nil {
		close(s.sourceStop)
	}
	return nil
}

func (s *Stream) sourceRoutine() {
	ticker := time.NewTicker(10 * time.Millisecond)
	defer ticker.Stop()

	defer func() {
		s.pipe.Close()
		s.sourceStop = nil
	}()

	stop := s.sourceStop
	int16Buffer := make([]int16, gumble.AudioDefaultFrameSize)
	byteBuffer := make([]byte, gumble.AudioDefaultFrameSize*2)
<commit_msg>gumble_ffmpeg: add IsPlaying, better handling of ffmpeg process<commit_after>package gumble_ffmpeg

import (
	"encoding/binary"
	"errors"
	"io"
	"os/exec"
	"strconv"
	"time"

	"github.com/layeh/gumble/gumble"
)

type Stream struct {
	client     *gumble.Client
	cmd        *exec.Cmd
	pipe       io.ReadCloser
	sourceStop chan bool
}

func New(client *gumble.Client) (*Stream, error) {
	stream := &Stream{
		client: client,
	}
	return stream, nil
}

func (s *Stream) Play(file string) error {
	if s.sourceStop != nil {
		return errors.New("already playing")
	}
	s.cmd = exec.Command("ffmpeg", "-i", file, "-ac", "1", "-ar", strconv.Itoa(gumble.AudioSampleRate), "-f", "s16le", "-")
	if pipe, err := s.cmd.StdoutPipe(); err != nil {
		s.cmd = nil
		return nil
	} else {
		s.pipe = pipe
	}
	s.sourceStop = make(chan bool)
	go s.sourceRoutine()
	s.cmd.Start()
	return nil
}

func (s *Stream) IsPlaying() bool {
	return s.sourceStop != nil
}

func (s *Stream) Stop() error {
	if s.sourceStop != nil {
		close(s.sourceStop)
		s.cmd.Wait()
	}
	return nil
}

func (s *Stream) sourceRoutine() {
	ticker := time.NewTicker(10 * time.Millisecond)
	defer ticker.Stop()

	defer func() {
		s.cmd.Process.Kill()
		s.cmd = nil
		s.sourceStop = nil
	}()

	stop := s.sourceStop
	int16Buffer := make([]int16, gumble.AudioDefaultFrameSize)
	byteBuffer := make([]byte, gumble.AudioDefaultFrameSize*2)

{'fraction_non_alphanumeric': 0.15881458966565348, 'fraction_numerical': 0.007598784194528876, 'mean_word_length': 3.619298245614035, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4487489', 'n_tokens_mistral': 1064, 'n_tokens_neox': 1025, 'n_words': 241}