Add basic logging support

This commit is contained in:
Rob Watson 2021-11-16 07:48:30 +01:00
parent fec542ee62
commit 911de4438b
10 changed files with 162 additions and 110 deletions

View File

@ -13,6 +13,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/kkdai/youtube/v2"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
const (
@ -42,7 +43,7 @@ func main() {
var youtubeClient youtube.Client
// Create a MediaSetService
mediaSetService := media.NewMediaSetService(store, &youtubeClient, s3Client)
mediaSetService := media.NewMediaSetService(store, &youtubeClient, s3Client, zap.NewNop())
mediaSet, err := mediaSetService.Get(ctx, videoID)
if err != nil {

View File

@ -8,10 +8,12 @@ require (
github.com/aws/aws-sdk-go-v2/service/s3 v1.17.0
github.com/aws/smithy-go v1.8.1
github.com/google/uuid v1.1.2
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/improbable-eng/grpc-web v0.14.1
github.com/kkdai/youtube/v2 v2.7.4
github.com/lib/pq v1.10.3
github.com/stretchr/testify v1.7.0
go.uber.org/zap v1.19.1
google.golang.org/grpc v1.41.0
google.golang.org/protobuf v1.26.0
)
@ -33,6 +35,8 @@ require (
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/cors v1.7.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
golang.org/x/net v0.0.0-20210913180222-943fd674d43e // indirect
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect
golang.org/x/text v0.3.7 // indirect

View File

@ -87,6 +87,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.8.0 h1:7N7RsEVvUcvEg7jrWKU5AnSi4/6b6
github.com/aws/aws-sdk-go-v2/service/sts v1.8.0/go.mod h1:dOlm91B439le5y1vtPCk5yJtbx3RdT3hRGYRY8TYKvQ=
github.com/aws/smithy-go v1.8.1 h1:9Y6qxtzgEODaLNGN+oN2QvcHvKUe4jsH8w4M+8LXzGk=
github.com/aws/smithy-go v1.8.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
@ -185,6 +187,7 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -266,6 +269,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
@ -408,6 +413,7 @@ github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
@ -523,13 +529,21 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723 h1:sHOAIxRGBp443oHZIPB+HsUGaksVCXVQENPxwTfQdH4=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -776,6 +790,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -1,13 +1,7 @@
package media
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"os"
"time"
"github.com/google/uuid"
@ -45,7 +39,7 @@ type MediaSet struct {
ID uuid.UUID `json:"id"`
YoutubeID string `json:"youtube_id"`
exists bool `json:"exists"`
exists bool
}
// New builds a new MediaSet with the given ID.
@ -59,80 +53,3 @@ func (m *MediaSet) EncodedAudioPath() string { return fmt.Sprintf("cache/%s.m4a"
func (m *MediaSet) VideoPath() string { return fmt.Sprintf("cache/%s.mp4", m.YoutubeID) }
func (m *MediaSet) ThumbnailPath() string { return fmt.Sprintf("cache/%s.jpg", m.YoutubeID) }
func (m *MediaSet) MetadataPath() string { return fmt.Sprintf("cache/%s.json", m.YoutubeID) }
func (m *MediaSet) Exists() bool {
if m.YoutubeID == "" {
return false
}
if m.exists {
return true
}
if _, err := os.Stat(m.MetadataPath()); err == nil {
m.exists = true
return true
}
return false
}
func (m *MediaSet) Load() error {
if m.YoutubeID == "" {
return errors.New("error opening mediaset with blank ID")
}
metadataFile, err := os.Open(m.MetadataPath())
if err != nil {
return fmt.Errorf("error opening metadata file: %v", err)
}
defer func() { _ = metadataFile.Close() }()
if err := json.NewDecoder(metadataFile).Decode(m); err != nil {
return fmt.Errorf("error decoding metadata: %v", err)
}
return nil
}
func (m *MediaSet) Peaks(start, end int64, numBins int) ([][]int16, error) {
if !m.Exists() {
return nil, errors.New("cannot compute peaks for non-existent MediaSet")
}
var err error
fptr, err := os.Open(m.RawAudioPath())
if err != nil {
return nil, fmt.Errorf("audio open error: %v", err)
}
defer fptr.Close()
startByte := start * int64(m.Audio.Channels) * SizeOfInt16
if _, err = fptr.Seek(startByte, io.SeekStart); err != nil {
return nil, fmt.Errorf("audio seek error: %v", err)
}
numFrames := end - start
framesPerBin := numFrames / int64(numBins)
peaks := make([][]int16, m.Audio.Channels)
for i := 0; i < m.Audio.Channels; i++ {
peaks[i] = make([]int16, numBins)
}
samples := make([]int16, framesPerBin*int64(m.Audio.Channels))
for binNum := 0; binNum < numBins; binNum++ {
if err := binary.Read(fptr, binary.LittleEndian, samples); err != nil {
return nil, fmt.Errorf("error reading samples: %v", err)
}
for i, samp := range samples {
if samp < 0 {
samp = -samp
}
chanIndex := i % m.Audio.Channels
if samp > peaks[chanIndex][binNum] {
peaks[chanIndex][binNum] = samp
}
}
}
log.Println("finished generating peaks")
return peaks, nil
}

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"database/sql"
"encoding/binary"
"errors"
"fmt"
"io"
@ -16,6 +17,7 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/google/uuid"
youtubev2 "github.com/kkdai/youtube/v2"
"go.uber.org/zap"
)
const s3Bucket = "clipper-development"
@ -76,13 +78,15 @@ type MediaSetService struct {
store Store
youtube YoutubeClient
s3 S3Client
logger *zap.SugaredLogger
}
func NewMediaSetService(store Store, youtubeClient YoutubeClient, s3Client S3Client) *MediaSetService {
func NewMediaSetService(store Store, youtubeClient YoutubeClient, s3Client S3Client, logger *zap.Logger) *MediaSetService {
return &MediaSetService{
store: store,
youtube: youtubeClient,
s3: s3Client,
logger: logger.Sugar(),
}
}
@ -418,6 +422,78 @@ func (s *getAudioFromYoutubeState) run(ctx context.Context, mediaSetID uuid.UUID
}
}
func (s *MediaSetService) GetAudioSegment(ctx context.Context, id uuid.UUID, startFrame, endFrame int64, numBins int) ([][]int16, error) {
mediaSet, err := s.store.GetMediaSet(ctx, id)
if err != nil {
return nil, fmt.Errorf("error getting media set: %v", err)
}
byteRange := fmt.Sprintf(
"bytes=%d-%d",
startFrame*int64(mediaSet.AudioChannels)*SizeOfInt16,
endFrame*int64(mediaSet.AudioChannels)*SizeOfInt16,
)
input := s3.GetObjectInput{
Bucket: aws.String(mediaSet.AudioS3Bucket.String),
Key: aws.String(mediaSet.AudioS3Key.String),
Range: aws.String(byteRange),
}
output, err := s.s3.GetObject(ctx, &input)
if err != nil {
return nil, fmt.Errorf("error getting object from s3: %v", err)
}
defer output.Body.Close()
modReader := NewModuloBufReader(output.Body, int(mediaSet.AudioChannels)*SizeOfInt16)
bufSizeBytes := 8_192
buf := make([]byte, bufSizeBytes)
peaks := make([][]int16, mediaSet.AudioChannels)
for i := range peaks {
peaks[i] = make([]int16, numBins)
}
var currPeakIndex int
var currFrame int64
channels := int(mediaSet.AudioChannels)
totalFrames := endFrame - startFrame
framesPerBin := totalFrames / int64(numBins)
samples := make([]int16, bufSizeBytes/SizeOfInt16)
for {
n, err := modReader.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("read error: %v", err)
}
if err := binary.Read(bytes.NewReader(buf[:n]), binary.LittleEndian, samples); err != nil {
return nil, fmt.Errorf("error interpreting samples: %v", err)
}
for i := 0; i < len(samples); i += channels {
for j := 0; j < channels; j++ {
samp := samples[i+j]
if samp < 0 {
samp = -samp
}
if samp > peaks[currPeakIndex][j] {
peaks[currPeakIndex][j] = samp
}
}
currFrame++
if currFrame == framesPerBin {
currFrame = 0
}
}
}
return peaks, nil
}
func sqlString(s string) sql.NullString {
return sql.NullString{String: s, Valid: true}
}
@ -426,6 +502,8 @@ func sqlInt64(i int64) sql.NullInt64 {
return sql.NullInt64{Int64: i, Valid: true}
}
// ModuloBufReader reads from a reader in block sizes that are exactly modulo
// modSize, with any remainder buffered until the next read.
type ModuloBufReader struct {
io.ReadCloser

View File

@ -14,6 +14,9 @@ import (
"github.com/aws/aws-sdk-go-v2/service/s3/types"
)
// multipartUploader uploads a file to S3.
//
// TODO: extract to s3 package
type multipartUploader struct {
s3 S3Client
}

View File

@ -4,26 +4,21 @@ import (
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
pbMediaSet "git.netflux.io/rob/clipper/generated/pb/media_set"
"git.netflux.io/rob/clipper/media"
"github.com/google/uuid"
grpczap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
"github.com/improbable-eng/grpc-web/go/grpcweb"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/durationpb"
)
func init() {
grpclog.SetLogger(log.New(os.Stdout, "server: ", log.LstdFlags))
}
const (
// ts-proto generates code that automatically retries for a subset of gRPC
// response codes. To avoid invoking this behaviour, default to returning a
@ -34,6 +29,11 @@ const (
defaultResponseMessage = "An unexpected error occurred"
)
const (
getAudioTimeout = time.Minute * 5
getAudioSegmentTimeout = time.Second * 10
)
type ResponseError struct {
err error
s string
@ -63,10 +63,6 @@ type Options struct {
S3Client media.S3Client
}
const (
getAudioTimeout = time.Minute * 5
)
// mediaSetServiceController implements gRPC controller for MediaSetService
type mediaSetServiceController struct {
pbMediaSet.UnimplementedMediaSetServiceServer
@ -98,8 +94,10 @@ func (c *mediaSetServiceController) Get(ctx context.Context, request *pbMediaSet
return &result, nil
}
// GetAudio streams the progress report of GetAudio.
// GetAudio returns a stream of GetAudioProgress relating to the entire audio
// part of the MediaSet.
func (c *mediaSetServiceController) GetAudio(request *pbMediaSet.GetAudioRequest, stream pbMediaSet.MediaSetService_GetAudioServer) error {
// TODO: reduce timeout when fetching from S3
ctx, cancel := context.WithTimeout(context.Background(), getAudioTimeout)
defer cancel()
@ -139,15 +137,39 @@ func (c *mediaSetServiceController) GetAudio(request *pbMediaSet.GetAudioRequest
return nil
}
// GetAudioSegment returns a set of peaks for a segment of an audio part of a
// MediaSet.
func (c *mediaSetServiceController) GetAudioSegment(ctx context.Context, request *pbMediaSet.GetAudioSegmentRequest) (*pbMediaSet.GetAudioSegmentResponse, error) {
ctx, cancel := context.WithTimeout(ctx, getAudioSegmentTimeout)
defer cancel()
id, err := uuid.Parse(request.GetId())
if err != nil {
return nil, newResponseError(err)
}
_, err = c.mediaSetService.GetAudioSegment(ctx, id, request.StartFrame, request.EndFrame, int(request.GetNumBins()))
if err != nil {
return nil, newResponseError(err)
}
return nil, nil
}
func Start(options Options) error {
grpcServer := grpc.NewServer()
logger, _ := zap.NewDevelopment()
defer logger.Sync()
fetchMediaSetService := media.NewMediaSetService(options.Store, options.YoutubeClient, options.S3Client)
grpcServer := grpc.NewServer(
grpc.UnaryInterceptor(grpczap.UnaryServerInterceptor(logger)),
)
fetchMediaSetService := media.NewMediaSetService(options.Store, options.YoutubeClient, options.S3Client, logger)
pbMediaSet.RegisterMediaSetServiceServer(grpcServer, &mediaSetServiceController{mediaSetService: fetchMediaSetService})
// TODO: configure CORS
grpcWebServer := grpcweb.WrapServer(grpcServer, grpcweb.WithOriginFunc(func(string) bool { return true }))
handler := func(w http.ResponseWriter, r *http.Request) {
grpcWebServer.ServeHTTP(w, r)
}

View File

@ -15,7 +15,6 @@
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"ts-proto": "^1.83.3",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
@ -50,6 +49,7 @@
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-react": "^7.25.1",
"prettier": "2.4.0",
"rxjs": "^7.4.0"
"rxjs": "^7.4.0",
"ts-proto": "^1.85.0"
}
}

View File

@ -1881,9 +1881,9 @@
integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
"@types/node@>=13.7.0":
version "16.11.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.6.tgz#6bef7a2a0ad684cf6e90fcfe31cecabd9ce0a3ae"
integrity sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==
version "16.11.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42"
integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==
"@types/node@^12.0.0":
version "12.20.23"
@ -11196,10 +11196,10 @@ ts-proto-descriptors@^1.2.1:
long "^4.0.0"
protobufjs "^6.8.8"
ts-proto@^1.83.3:
version "1.83.3"
resolved "https://registry.yarnpkg.com/ts-proto/-/ts-proto-1.83.3.tgz#ada7483035ddc946aa686dad1049e4fe45ae1d0f"
integrity sha512-r6MKFjoc4Og2kB4cNJ/bddLebdIwhouG5plu0Rry1jJMEqp2GKA7AE4FrR/FnTCIGbNPYP4622lBqckZd7UHcQ==
ts-proto@^1.85.0:
version "1.85.0"
resolved "https://registry.yarnpkg.com/ts-proto/-/ts-proto-1.85.0.tgz#a46925423a4df576f2fcf483d0d4b1ff2530d0ea"
integrity sha512-wYDzMl8LVqV8K65oI463KSIkfAxd3ulzMqZD+5NYWawwKfkJVNfTXjK847NJEHt4UBxSLZ0+aBjuc++cFNAUvw==
dependencies:
"@types/object-hash" "^1.3.0"
dataloader "^1.4.0"

View File

@ -22,8 +22,8 @@ message MediaSet {
};
message GetAudioProgress {
float percent_completed = 2;
repeated int32 peaks = 1;
float percent_completed = 2;
}
message GetRequest {
@ -35,7 +35,19 @@ message GetAudioRequest {
int32 num_bins = 2;
}
message GetAudioSegmentRequest {
string id = 1;
int32 num_bins = 2;
int64 start_frame = 3;
int64 end_frame = 4;
}
message GetAudioSegmentResponse {
repeated int32 peaks = 1;
}
service MediaSetService {
rpc Get(GetRequest) returns (MediaSet) {}
rpc GetAudio(GetAudioRequest) returns (stream GetAudioProgress) {}
rpc GetAudioSegment(GetAudioSegmentRequest) returns (GetAudioSegmentResponse) {}
}