Skip to main content
Glama
manager.go4.92 kB
package scrcpy import ( "context" "sync" "github.com/babelcloud/gbox/packages/cli/internal/util" ) // GlobalManager manages shared scrcpy sources per device type GlobalManager struct { mu sync.RWMutex sources map[string]*Source } var globalManager = &GlobalManager{ sources: make(map[string]*Source), } // GetOrCreateSource returns an existing source or creates a new one func GetOrCreateSource(deviceSerial string) *Source { return GetOrCreateSourceWithMode(deviceSerial, "webrtc") // Default mode } // GetOrCreateSourceWithMode returns an existing source or creates a new one with specific mode func GetOrCreateSourceWithMode(deviceSerial string, streamingMode string) *Source { globalManager.mu.Lock() defer globalManager.mu.Unlock() if src, exists := globalManager.sources[deviceSerial]; exists { // Check if source is still valid (has active cancel function) src.mu.Lock() if src.cancel != nil { // Source is still active, check if streaming mode change requires restart if src.streamingMode != streamingMode { // Check if audio codec needs to change (requires server restart) needsRestart := needsAudioCodecRestart(src.streamingMode, streamingMode) if needsRestart { util.GetLogger().Info("Audio codec change detected, restarting scrcpy server", "device", deviceSerial, "from", src.streamingMode, "to", streamingMode) // Stop the existing source to force restart with new codec src.mu.Unlock() src.Stop() // Remove from manager and create new one globalManager.mu.Unlock() globalManager.mu.Lock() delete(globalManager.sources, deviceSerial) } else { // Just update the mode without restart util.GetLogger().Info("Updating streaming mode without restart", "device", deviceSerial, "from", src.streamingMode, "to", streamingMode) src.streamingMode = streamingMode src.mu.Unlock() util.GetLogger().Info("Using existing scrcpy source", "device", deviceSerial, "mode", streamingMode) return src } } else { src.mu.Unlock() util.GetLogger().Info("Using existing scrcpy source", "device", deviceSerial, "mode", streamingMode) return src } } else { src.mu.Unlock() // Source exists but is not active, remove it and create a new one util.GetLogger().Info("Removing inactive scrcpy source", "device", deviceSerial) delete(globalManager.sources, deviceSerial) } } util.GetLogger().Info("Creating new scrcpy source", "device", deviceSerial, "mode", streamingMode) src := NewSourceWithMode(deviceSerial, streamingMode) globalManager.sources[deviceSerial] = src return src } // StartSource starts a source if not already started func StartSource(deviceSerial string, ctx context.Context) (*Source, error) { return StartSourceWithMode(deviceSerial, ctx, "webrtc") // Default mode } // StartSourceWithMode starts a source with specific streaming mode func StartSourceWithMode(deviceSerial string, ctx context.Context, streamingMode string) (*Source, error) { src := GetOrCreateSourceWithMode(deviceSerial, streamingMode) // Check if already started src.mu.Lock() if src.cancel != nil { src.mu.Unlock() util.GetLogger().Info("Scrcpy source already started", "device", deviceSerial) return src, nil } src.mu.Unlock() // Start the source if err := src.Start(ctx, deviceSerial); err != nil { util.GetLogger().Error("Failed to start scrcpy source", "device", deviceSerial, "error", err) // If start failed, clean up the source state src.mu.Lock() src.cancel = nil src.mu.Unlock() return nil, err } util.GetLogger().Info("Scrcpy source started successfully", "device", deviceSerial) return src, nil } // RemoveSource removes a source from the global manager func RemoveSource(deviceSerial string) { globalManager.mu.Lock() defer globalManager.mu.Unlock() if src, exists := globalManager.sources[deviceSerial]; exists { src.Stop() delete(globalManager.sources, deviceSerial) util.GetLogger().Info("Removed scrcpy source", "device", deviceSerial) } } // GetSource returns an existing source if it exists func GetSource(deviceSerial string) *Source { globalManager.mu.RLock() defer globalManager.mu.RUnlock() return globalManager.sources[deviceSerial] } // needsAudioCodecRestart determines if a streaming mode change requires server restart // due to audio codec differences func needsAudioCodecRestart(fromMode, toMode string) bool { // Define audio codec groups aacModes := []string{"mp4", "muxed"} // Helper function to check if mode uses AAC codec isAACMode := func(mode string) bool { for _, m := range aacModes { if mode == m { return true } } return false } // Check if switching between different audio codec groups fromIsAAC := isAACMode(fromMode) toIsAAC := isAACMode(toMode) // If switching from AAC to Opus or vice versa, restart is needed return fromIsAAC != toIsAAC }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babelcloud/gru-sandbox'

If you have feedback or need assistance with the MCP directory API, please join our Discord server